home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / var / lib / python-support / python2.6 / orca / structural_navigation.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  90.3 KB  |  2,813 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''Implements structural navigation.  Right now this is only
  5. being implemented by Gecko; however it can be used in any
  6. script providing access to document content.'''
  7. __id__ = '$Id: structural_navigation.py 4507 2009-02-08 19:37:37Z wwalker $'
  8. __version__ = '$Revision: 4507 $'
  9. __date__ = '$Date: 2009-02-08 14:37:37 -0500 (Sun, 08 Feb 2009) $'
  10. __copyright__ = 'Copyright (c) 2005-2008 Sun Microsystems Inc.'
  11. __license__ = 'LGPL'
  12. import pyatspi
  13. import braille
  14. import debug
  15. import input_event
  16. import keybindings
  17. import orca
  18. import orca_state
  19. import settings
  20. import speech
  21. from orca_i18n import _
  22. from orca_i18n import ngettext
  23.  
  24. class MatchCriteria:
  25.     """Contains the criteria which will be used to generate a collection
  26.     matchRule.  We don't want to create the rule until we need it and
  27.     are ready to use it. In addition, the creation of an AT-SPI match
  28.     rule requires you specify quite a few things (see the __init__),
  29.     most of which are irrelevant to the search at hand.  This class
  30.     makes it possible for the StructuralNavigationObject creator to just
  31.     specify the few criteria that actually matter.
  32.     """
  33.     
  34.     def __init__(self, collection, states = [], matchStates = None, objAttrs = [], matchObjAttrs = None, roles = [], matchRoles = None, interfaces = '', matchInterfaces = None, invert = False, applyPredicate = False):
  35.         """Creates a new match criteria object.
  36.  
  37.         Arguments:
  38.         - collection: the collection interface for the document in
  39.           which the accessible objects can be found.
  40.         - states: a list of pyatspi states of interest
  41.         - matchStates: whether an object must have all of the states
  42.           in the states list, any of the states in the list, or none
  43.           of the states in the list.  Must be one of the collection
  44.           interface MatchTypes if provided.
  45.         - objAttrs: a list of object attributes (not text attributes)
  46.         - matchObjAttrs: whether an object must have all of the
  47.           attributes in the objAttrs list, any of the attributes in
  48.           the list, or none of the attributes in the list.  Must be
  49.           one of the collection interface MatchTypes if provided.
  50.         - interfaces: (We aren't using this.  According to the at-spi
  51.           idl, it is a string.)
  52.         - matchInterfaces: The collection MatchType for matching by
  53.           interface.
  54.         - invert: If true the match rule will find objects that don't
  55.           match. We always use False.
  56.         - applyPredicate: whether or not a predicate should be applied
  57.           as an additional check to see if an item is indeed a match.
  58.           This is necessary, for instance, when one of the things we
  59.           care about is a text attribute, something the collection
  60.           interface doesn't include in its criteria.
  61.         """
  62.         self.collection = collection
  63.         if not matchStates:
  64.             pass
  65.         self.matchStates = collection.MATCH_ANY
  66.         self.objAttrs = objAttrs
  67.         if not matchObjAttrs:
  68.             pass
  69.         self.matchObjAttrs = collection.MATCH_ANY
  70.         self.roles = roles
  71.         if not matchRoles:
  72.             pass
  73.         self.matchRoles = collection.MATCH_ANY
  74.         self.interfaces = interfaces
  75.         if not matchInterfaces:
  76.             pass
  77.         self.matchInterfaces = collection.MATCH_ALL
  78.         self.invert = invert
  79.         self.applyPredicate = applyPredicate
  80.         self.states = pyatspi.StateSet()
  81.         for state in states:
  82.             self.states.add(state)
  83.         
  84.  
  85.  
  86.  
  87. class StructuralNavigationObject:
  88.     '''Represents a document object which has identifiable characteristics
  89.     which can be used for the purpose of navigation to and among instances
  90.     of that object. These characteristics may be something as simple as a
  91.     role and/or a state of interest. Or they may be something more complex
  92.     such as character counts, text attributes, and other object attributes.
  93.     '''
  94.     
  95.     def __init__(self, structuralNavigation, objType, bindings, predicate, criteria, presentation):
  96.         '''Creates a new structural navigation object.
  97.  
  98.         Arguments:
  99.         - structuralNavigation: the StructuralNavigation class associated
  100.           with this object.
  101.         - objType: the type (e.g. BLOCKQUOTE) associated with this object.
  102.         - bindings: a dictionary of all of the possible bindings for this
  103.           object.  In the case of all but the "atLevel" bindings, each
  104.           binding takes the form of [keysymstring, modifiers, description].
  105.           The goPreviousAtLevel and goNextAtLevel bindings are each a list
  106.           of bindings in that form.
  107.         - predicate: the predicate to use to determine if a given accessible
  108.           matches this structural navigation object. Used when a search via
  109.           collection is not possible or practical.
  110.         - criteria: a method which returns a MatchCriteria object which
  111.           can in turn be used to locate the next/previous matching accessible
  112.           via collection.
  113.         - presentation: the method which should be called after performing
  114.           the search for the structural navigation object.
  115.         '''
  116.         self.structuralNavigation = structuralNavigation
  117.         self.objType = objType
  118.         self.bindings = bindings
  119.         self.predicate = predicate
  120.         self.criteria = criteria
  121.         self.present = presentation
  122.         self.inputEventHandlers = { }
  123.         self.keyBindings = keybindings.KeyBindings()
  124.         self.functions = []
  125.         self._setUpHandlersAndBindings()
  126.  
  127.     
  128.     def _setUpHandlersAndBindings(self):
  129.         '''Adds the inputEventHandlers and keyBindings for this object.'''
  130.         previous = self.bindings.get('previous')
  131.         if previous:
  132.             (keysymstring, modifiers, description) = previous
  133.             handlerName = '%sGoPrevious' % self.objType
  134.             self.inputEventHandlers[handlerName] = input_event.InputEventHandler(self.goPrevious, description)
  135.             self.keyBindings.add(keybindings.KeyBinding(keysymstring, settings.defaultModifierMask, modifiers, self.inputEventHandlers[handlerName]))
  136.             self.functions.append(self.goPrevious)
  137.         
  138.         next = self.bindings.get('next')
  139.         if next:
  140.             (keysymstring, modifiers, description) = next
  141.             handlerName = '%sGoNext' % self.objType
  142.             self.inputEventHandlers[handlerName] = input_event.InputEventHandler(self.goNext, description)
  143.             self.keyBindings.add(keybindings.KeyBinding(keysymstring, settings.defaultModifierMask, modifiers, self.inputEventHandlers[handlerName]))
  144.             self.functions.append(self.goNext)
  145.         
  146.         if not self.bindings.get('previousAtLevel'):
  147.             pass
  148.         previousAtLevel = []
  149.         for i, binding in enumerate(previousAtLevel):
  150.             level = i + 1
  151.             handler = self.goPreviousAtLevelFactory(level)
  152.             handlerName = '%sGoPreviousLevel%dHandler' % (self.objType, level)
  153.             (keysymstring, modifiers, description) = binding
  154.             self.inputEventHandlers[handlerName] = input_event.InputEventHandler(handler, description)
  155.             self.keyBindings.add(keybindings.KeyBinding(keysymstring, settings.defaultModifierMask, modifiers, self.inputEventHandlers[handlerName]))
  156.             self.functions.append(handler)
  157.         
  158.         if not self.bindings.get('nextAtLevel'):
  159.             pass
  160.         nextAtLevel = []
  161.         for i, binding in enumerate(nextAtLevel):
  162.             level = i + 1
  163.             handler = self.goNextAtLevelFactory(level)
  164.             handlerName = '%sGoNextLevel%dHandler' % (self.objType, level)
  165.             (keysymstring, modifiers, description) = binding
  166.             self.inputEventHandlers[handlerName] = input_event.InputEventHandler(handler, description)
  167.             self.keyBindings.add(keybindings.KeyBinding(keysymstring, settings.defaultModifierMask, modifiers, self.inputEventHandlers[handlerName]))
  168.             self.functions.append(handler)
  169.         
  170.         directions = { }
  171.         directions['Left'] = self.bindings.get('left')
  172.         directions['Right'] = self.bindings.get('right')
  173.         directions['Up'] = self.bindings.get('up')
  174.         directions['Down'] = self.bindings.get('down')
  175.         directions['First'] = self.bindings.get('first')
  176.         directions['Last'] = self.bindings.get('last')
  177.         for direction in directions:
  178.             binding = directions.get(direction)
  179.             if not binding:
  180.                 continue
  181.             
  182.             handler = self.goDirectionFactory(direction)
  183.             handlerName = '%sGo%s' % (self.objType, direction)
  184.             (keysymstring, modifiers, description) = binding
  185.             self.inputEventHandlers[handlerName] = input_event.InputEventHandler(handler, description)
  186.             self.keyBindings.add(keybindings.KeyBinding(keysymstring, settings.defaultModifierMask, modifiers, self.inputEventHandlers[handlerName]))
  187.             self.functions.append(handler)
  188.         
  189.  
  190.     
  191.     def addHandlerAndBinding(self, binding, handlerName, function):
  192.         """Adds a custom inputEventHandler and keybinding to the object's
  193.         handlers and bindings.  Right now this is unused, but here in
  194.         case a creator of a StructuralNavigationObject had some other
  195.         desired functionality in mind.
  196.  
  197.         Arguments:
  198.         - binding: [keysymstring, modifiers, description]
  199.         - handlerName: a string uniquely identifying the handler
  200.         - function: the function associated with the binding
  201.         """
  202.         (keysymstring, modifiers, description) = binding
  203.         handler = input_event.InputEventHandler(function, description)
  204.         keyBinding = keybindings.KeyBinding(keysymstring, settings.defaultModifierMask, modifiers, handler)
  205.         self.inputEventHandlers[handlerName] = handler
  206.         self.structuralNavigation.inputEventHandlers[handlerName] = handler
  207.         self.functions.append(function)
  208.         self.structuralNavigation.functions.append(function)
  209.         self.keyBindings.add(keyBinding)
  210.         self.structuralNavigation.keyBindings.add(keyBinding)
  211.  
  212.     
  213.     def goPrevious(self, script, inputEvent):
  214.         '''Go to the previous object.'''
  215.         self.structuralNavigation.goObject(self, False)
  216.  
  217.     
  218.     def goNext(self, script, inputEvent):
  219.         '''Go to the next object.'''
  220.         self.structuralNavigation.goObject(self, True)
  221.  
  222.     
  223.     def goPreviousAtLevelFactory(self, level):
  224.         '''Generates a goPrevious method for the specified level. Right
  225.         now, this is just for headings, but it may have applicability
  226.         for other objects such as list items (i.e. for level-based
  227.         navigation in an outline or other multi-tiered list.
  228.  
  229.         Arguments:
  230.         - level: the desired level of the object as an int.
  231.         '''
  232.         
  233.         def goPreviousAtLevel(script, inputEvent):
  234.             self.structuralNavigation.goObject(self, False, arg = level)
  235.  
  236.         return goPreviousAtLevel
  237.  
  238.     
  239.     def goNextAtLevelFactory(self, level):
  240.         '''Generates a goNext method for the specified level. Right
  241.         now, this is just for headings, but it may have applicability
  242.         for other objects such as list items (i.e. for level-based
  243.         navigation in an outline or other multi-tiered list.
  244.  
  245.         Arguments:
  246.         - level: the desired level of the object as an int.
  247.  
  248.         '''
  249.         
  250.         def goNextAtLevel(script, inputEvent):
  251.             self.structuralNavigation.goObject(self, True, arg = level)
  252.  
  253.         return goNextAtLevel
  254.  
  255.     
  256.     def goDirectionFactory(self, direction):
  257.         '''Generates the methods for navigation in a particular direction
  258.         (i.e. left, right, up, down, first, last).  Right now, this is
  259.         primarily for table cells, but it may have applicability for other
  260.         objects.  For example, when navigating in an outline, one might
  261.         want the ability to navigate to the next item at a given level,
  262.         but then work his/her way up/down in the hierarchy.
  263.  
  264.         Arguments:
  265.         - direction: the direction in which to navigate as a string.
  266.         '''
  267.         
  268.         def goCell(script, inputEvent):
  269.             thisCell = self.structuralNavigation.getCellForObj(self.structuralNavigation.getCurrentObject())
  270.             currentCoordinates = self.structuralNavigation.getCellCoordinates(thisCell)
  271.             if direction == 'Left':
  272.                 desiredCoordinates = [
  273.                     currentCoordinates[0],
  274.                     currentCoordinates[1] - 1]
  275.             elif direction == 'Right':
  276.                 desiredCoordinates = [
  277.                     currentCoordinates[0],
  278.                     currentCoordinates[1] + 1]
  279.             elif direction == 'Up':
  280.                 desiredCoordinates = [
  281.                     currentCoordinates[0] - 1,
  282.                     currentCoordinates[1]]
  283.             elif direction == 'Down':
  284.                 desiredCoordinates = [
  285.                     currentCoordinates[0] + 1,
  286.                     currentCoordinates[1]]
  287.             elif direction == 'First':
  288.                 desiredCoordinates = [
  289.                     0,
  290.                     0]
  291.             else:
  292.                 desiredCoordinates = [
  293.                     -1,
  294.                     -1]
  295.                 table = self.structuralNavigation.getTableForCell(thisCell)
  296.                 if table:
  297.                     iTable = table.queryTable()
  298.                     lastRow = iTable.nRows - 1
  299.                     lastCol = iTable.nColumns - 1
  300.                     desiredCoordinates = [
  301.                         lastRow,
  302.                         lastCol]
  303.                 
  304.             self.structuralNavigation.goCell(self, thisCell, currentCoordinates, desiredCoordinates)
  305.  
  306.         
  307.         def goLastLiveRegion(script, inputEvent):
  308.             '''Go to the last liveRegion.'''
  309.             if settings.inferLiveRegions:
  310.                 script.liveMngr.goLastLiveRegion()
  311.             else:
  312.                 speech.speak(_('Live region support is off'))
  313.  
  314.         if self.objType == StructuralNavigation.TABLE_CELL:
  315.             return goCell
  316.         if self.objType == StructuralNavigation.LIVE_REGION and direction == 'Last':
  317.             return goLastLiveRegion
  318.  
  319.  
  320.  
  321. class StructuralNavigation:
  322.     '''This class implements the structural navigation functionality which
  323.     is available to scripts. Scripts interested in implementing structural
  324.     navigation need to override getEnabledStructuralNavigationTypes() and
  325.     return a list of StructuralNavigation object types which should be
  326.     enabled.
  327.     '''
  328.     ANCHOR = 'anchor'
  329.     BLOCKQUOTE = 'blockquote'
  330.     BUTTON = 'button'
  331.     CHECK_BOX = 'checkBox'
  332.     CHUNK = 'chunk'
  333.     COMBO_BOX = 'comboBox'
  334.     ENTRY = 'entry'
  335.     FORM_FIELD = 'formField'
  336.     HEADING = 'heading'
  337.     LANDMARK = 'landmark'
  338.     LIST = 'list'
  339.     LIST_ITEM = 'listItem'
  340.     LIVE_REGION = 'liveRegion'
  341.     PARAGRAPH = 'paragraph'
  342.     RADIO_BUTTON = 'radioButton'
  343.     TABLE = 'table'
  344.     TABLE_CELL = 'tableCell'
  345.     UNVISITED_LINK = 'unvisitedLink'
  346.     VISITED_LINK = 'visitedLink'
  347.     collectionEnabled = settings.useCollection
  348.     FORM_ROLES = [
  349.         pyatspi.ROLE_CHECK_BOX,
  350.         pyatspi.ROLE_RADIO_BUTTON,
  351.         pyatspi.ROLE_COMBO_BOX,
  352.         pyatspi.ROLE_LIST,
  353.         pyatspi.ROLE_ENTRY,
  354.         pyatspi.ROLE_PASSWORD_TEXT,
  355.         pyatspi.ROLE_PUSH_BUTTON,
  356.         pyatspi.ROLE_SPIN_BUTTON,
  357.         pyatspi.ROLE_TEXT]
  358.     OBJECT_ROLES = [
  359.         pyatspi.ROLE_HEADING,
  360.         pyatspi.ROLE_LIST,
  361.         pyatspi.ROLE_PARAGRAPH,
  362.         pyatspi.ROLE_TABLE,
  363.         pyatspi.ROLE_TABLE_CELL,
  364.         pyatspi.ROLE_TEXT,
  365.         pyatspi.ROLE_SECTION,
  366.         pyatspi.ROLE_DOCUMENT_FRAME]
  367.     
  368.     def __init__(self, script, enabledTypes, enabled = False):
  369.         '''Creates an instance of the StructuralNavigation class.
  370.  
  371.         Arguments:
  372.         - script: the script which which this instance is associated.
  373.         - enabledTypes: a list of StructuralNavigation object types
  374.           which the script is interested in supporting.
  375.         - enabled: Whether structural navigation should start out
  376.           enabled.  For instance, in Gecko by default we do what it
  377.           enabled; in soffice, we would want to start out with it
  378.           disabled and have the user enable it via a keystroke when
  379.           desired.
  380.         '''
  381.         self._script = script
  382.         self.enabled = enabled
  383.         self.enabledObjects = { }
  384.         for objType in enabledTypes:
  385.             self.enabledObjects[objType] = self.structuralNavigationObjectCreator(objType)
  386.         
  387.         self.functions = []
  388.         self.inputEventHandlers = { }
  389.         self.setupInputEventHandlers()
  390.         self.keyBindings = self.getKeyBindings()
  391.         self.lastTableCell = [
  392.             -1,
  393.             -1]
  394.  
  395.     
  396.     def structuralNavigationObjectCreator(self, name):
  397.         '''This convenience method creates a StructuralNavigationObject
  398.         with the specified name and associated characterists. (See the
  399.         "Objects" section of code near the end of this class. Creators
  400.         of StructuralNavigationObject\'s can still do things the old
  401.         fashioned way should they so choose, by creating the instance
  402.         and then adding it via addObject().
  403.  
  404.         Arguments:
  405.         - name: the name/objType associated with this object.
  406.         '''
  407.         bindings = eval('self._%sBindings()' % name)
  408.         predicate = eval('self._%sPredicate' % name)
  409.         presentation = eval('self._%sPresentation' % name)
  410.         
  411.         try:
  412.             criteria = eval('self._%sCriteria' % name)
  413.         except:
  414.             criteria = None
  415.  
  416.         return StructuralNavigationObject(self, name, bindings, predicate, criteria, presentation)
  417.  
  418.     
  419.     def addObject(self, objType, structuralNavigationObject):
  420.         '''Adds structuralNavigationObject to the dictionary of enabled
  421.         objects.
  422.  
  423.         Arguments:
  424.         - objType: the name/object type of the StructuralNavigationObject.
  425.         - structuralNavigationObject: the StructuralNavigationObject to
  426.           add.
  427.         '''
  428.         self.enabledObjects[objType] = structuralNavigationObject
  429.  
  430.     
  431.     def setupInputEventHandlers(self):
  432.         '''Defines InputEventHandler fields for a script.'''
  433.         if not len(self.enabledObjects):
  434.             return None
  435.         self.inputEventHandlers['toggleStructuralNavigationHandler'] = input_event.InputEventHandler(self.toggleStructuralNavigation, _('Toggles structural navigation keys.'))
  436.         for structuralNavigationObject in self.enabledObjects.values():
  437.             self.inputEventHandlers.update(structuralNavigationObject.inputEventHandlers)
  438.             self.functions.extend(structuralNavigationObject.functions)
  439.         
  440.  
  441.     
  442.     def getKeyBindings(self):
  443.         '''Defines the structural navigation key bindings for a script.
  444.  
  445.         Returns: an instance of keybindings.KeyBindings.
  446.         '''
  447.         keyBindings = keybindings.KeyBindings()
  448.         if not len(self.enabledObjects):
  449.             return keyBindings
  450.         keyBindings.add(keybindings.KeyBinding('z', settings.defaultModifierMask, settings.ORCA_MODIFIER_MASK, self.inputEventHandlers['toggleStructuralNavigationHandler']))
  451.         for structuralNavigationObject in self.enabledObjects.values():
  452.             bindings = structuralNavigationObject.keyBindings.keyBindings
  453.             for keybinding in bindings:
  454.                 keyBindings.add(keybinding)
  455.             
  456.         
  457.         return keyBindings
  458.  
  459.     
  460.     def toggleStructuralNavigation(self, script, inputEvent):
  461.         '''Toggles structural navigation keys.'''
  462.         self.enabled = not (self.enabled)
  463.         if self.enabled:
  464.             string = _('Structural navigation keys on.')
  465.         else:
  466.             string = _('Structural navigation keys off.')
  467.         debug.println(debug.LEVEL_CONFIGURATION, string)
  468.         speech.speak(string)
  469.         braille.displayMessage(string)
  470.  
  471.     
  472.     def goCell(self, structuralNavigationObject, thisCell, currentCoordinates, desiredCoordinates):
  473.         """The method used for navigation among cells in a table.
  474.  
  475.         Arguments:
  476.         - structuralNavigationObject: the StructuralNavigationObject which
  477.           represents the table cell.
  478.         - thisCell: the pyatspi accessible TABLE_CELL we're currently in
  479.         - currentCoordinates: the [row, column] of thisCell.  Note, we
  480.           cannot just get the coordinates because in table cells which
  481.           span multiple rows and/or columns, the value returned by 
  482.           table.getRowAtIndex() is the first row the cell spans. Likewise,
  483.           the value returned by table.getColumnAtIndex() is the left-most
  484.           column.  Therefore, we keep track of the row and column from
  485.           our perspective to ensure we stay in the correct row and column.
  486.         - desiredCoordinates: the [row, column] where we think we'd like to
  487.           be.
  488.         """
  489.         table = self.getTableForCell(thisCell)
  490.         
  491.         try:
  492.             iTable = table.queryTable()
  493.         except:
  494.             speech.speak(_('Not in a table.'))
  495.             return None
  496.  
  497.         (currentRow, currentCol) = currentCoordinates
  498.         (desiredRow, desiredCol) = desiredCoordinates
  499.         rowDiff = desiredRow - currentRow
  500.         colDiff = desiredCol - currentCol
  501.         oldRowHeaders = self._getRowHeaders(thisCell)
  502.         oldColHeaders = self._getColumnHeaders(thisCell)
  503.         cell = thisCell
  504.         while cell:
  505.             cell = iTable.getAccessibleAt(desiredRow, desiredCol)
  506.             if not cell:
  507.                 if desiredCol < 0:
  508.                     speech.speak(_('Beginning of row.'))
  509.                     desiredCol = 0
  510.                 elif desiredCol > iTable.nColumns - 1:
  511.                     speech.speak(_('End of row.'))
  512.                     desiredCol = iTable.nColumns - 1
  513.                 
  514.                 if desiredRow < 0:
  515.                     speech.speak(_('Top of column.'))
  516.                     desiredRow = 0
  517.                 elif desiredRow > iTable.nRows - 1:
  518.                     speech.speak(_('Bottom of column.'))
  519.                     desiredRow = iTable.nRows - 1
  520.                 
  521.             desiredRow < 0
  522.             if (self._script.isSameObject(thisCell, cell) or settings.skipBlankCells) and self._isBlankCell(cell):
  523.                 if colDiff < 0:
  524.                     desiredCol -= 1
  525.                 elif colDiff > 0:
  526.                     desiredCol += 1
  527.                 
  528.                 if rowDiff < 0:
  529.                     desiredRow -= 1
  530.                 elif rowDiff > 0:
  531.                     desiredRow += 1
  532.                 
  533.             rowDiff < 0
  534.             break
  535.         self.lastTableCell = [
  536.             desiredRow,
  537.             desiredCol]
  538.         if cell:
  539.             arg = [
  540.                 rowDiff,
  541.                 colDiff,
  542.                 oldRowHeaders,
  543.                 oldColHeaders]
  544.             structuralNavigationObject.present(cell, arg)
  545.         
  546.  
  547.     
  548.     def goObject(self, structuralNavigationObject, next, obj = None, arg = None):
  549.         """The method used for navigation among StructuralNavigationObjects
  550.         which are not table cells.
  551.  
  552.         Arguments:
  553.         - structuralNavigationObject: the StructuralNavigationObject which
  554.           represents the object of interest.
  555.         - next: If True, we're interested in the next accessible object
  556.           which matches structuralNavigationObject.  If False, we're 
  557.           interested in the previous accessible object which matches.
  558.         - obj: the current object (typically the locusOfFocus).
  559.         - arg: optional arguments which may need to be passed along to
  560.           the predicate, presentation method, etc. For instance, in the
  561.           case of navigating amongst headings at a given level, the level
  562.           is needed and passed in as arg.
  563.         """
  564.         if not obj:
  565.             pass
  566.         obj = self.getCurrentObject()
  567.         
  568.         try:
  569.             state = obj.getState()
  570.         except:
  571.             return [
  572.                 None,
  573.                 False]
  574.  
  575.         if state.contains(pyatspi.STATE_DEFUNCT):
  576.             debug.printException(debug.LEVEL_SEVERE)
  577.             return [
  578.                 None,
  579.                 False]
  580.         success = False
  581.         wrap = settings.wrappedStructuralNavigation
  582.         formObjects = [
  583.             self.BUTTON,
  584.             self.CHECK_BOX,
  585.             self.COMBO_BOX,
  586.             self.ENTRY,
  587.             self.FORM_FIELD,
  588.             self.RADIO_BUTTON]
  589.         criteria = None
  590.         objType = structuralNavigationObject.objType
  591.         if self.collectionEnabled and objType not in formObjects:
  592.             if next or objType != self.CHUNK:
  593.                 
  594.                 try:
  595.                     document = self._getDocument()
  596.                     collection = document.queryCollection()
  597.                     if structuralNavigationObject.criteria:
  598.                         criteria = structuralNavigationObject.criteria(collection, arg)
  599.                 except:
  600.                     state.contains(pyatspi.STATE_DEFUNCT)
  601.                     debug.printException(debug.LEVEL_SEVERE)
  602.  
  603.                 if next and self._script.isSameObject(obj, document):
  604.                     criteria = None
  605.                 
  606.             
  607.         if criteria:
  608.             
  609.             try:
  610.                 rule = collection.createMatchRule(criteria.states.raw(), criteria.matchStates, criteria.objAttrs, criteria.matchObjAttrs, criteria.roles, criteria.matchRoles, criteria.interfaces, criteria.matchInterfaces, criteria.invert)
  611.                 if criteria.applyPredicate:
  612.                     predicate = structuralNavigationObject.predicate
  613.                 else:
  614.                     predicate = None
  615.                 if not next:
  616.                     (obj, wrapped) = self._findPrevByMatchRule(collection, rule, wrap, obj, predicate)
  617.                 else:
  618.                     (obj, wrapped) = self._findNextByMatchRule(collection, rule, wrap, obj, predicate)
  619.                 success = True
  620.                 collection.freeMatchRule(rule)
  621.             except NotImplementedError:
  622.                 debug.printException(debug.LEVEL_SEVERE)
  623.             except:
  624.                 None<EXCEPTION MATCH>NotImplementedError
  625.                 debug.printException(debug.LEVEL_SEVERE)
  626.                 collection.freeMatchRule(rule)
  627.             
  628.  
  629.         None<EXCEPTION MATCH>NotImplementedError
  630.         if not success:
  631.             pred = structuralNavigationObject.predicate
  632.             if not next:
  633.                 (obj, wrapped) = self._findPrevByPredicate(pred, wrap, obj, arg)
  634.             else:
  635.                 (obj, wrapped) = self._findNextByPredicate(pred, wrap, obj, arg)
  636.         
  637.         if wrapped:
  638.             if not next:
  639.                 speech.speak(_('Wrapping to bottom.'))
  640.             else:
  641.                 speech.speak(_('Wrapping to top.'))
  642.         
  643.         structuralNavigationObject.present(obj, arg)
  644.  
  645.     
  646.     def getCurrentObject(self):
  647.         """Returns the current object.  Normally, the locusOfFocus. But
  648.         in the case of Gecko, that doesn't always work.
  649.         """
  650.         return orca_state.locusOfFocus
  651.  
  652.     
  653.     def _findPrevByMatchRule(self, collection, matchRule, wrap, currentObj, predicate = None):
  654.         '''Finds the previous object using the given match rule as a
  655.         pattern to match or not match.
  656.  
  657.         Arguments:
  658.         -collection: the accessible collection interface
  659.         -matchRule: the collections match rule to use
  660.         -wrap: if True and the bottom of the document is reached, move
  661.          to the top and keep looking.
  662.         -currentObj: the object from which the search should begin
  663.         -predicate: an optional predicate to further test if the item
  664.          found via collection is indeed a match.
  665.  
  666.         Returns: [obj, wrapped] where wrapped is a boolean reflecting
  667.         whether wrapping took place.
  668.         '''
  669.         if not currentObj:
  670.             pass
  671.         currentObj = self.getCurrentObject()
  672.         document = self._getDocument()
  673.         if self._script.isSameObject(currentObj, document):
  674.             currentObj = self._findNextObject(currentObj, document)
  675.         
  676.         ancestors = []
  677.         obj = currentObj.parent
  678.         if obj.getRole() in [
  679.             pyatspi.ROLE_LIST,
  680.             pyatspi.ROLE_TABLE]:
  681.             ancestors.append(obj)
  682.         else:
  683.             while obj:
  684.                 ancestors.append(obj)
  685.                 obj = obj.parent
  686.         match = None
  687.         wrapped = False
  688.         results = collection.getMatchesTo(currentObj, matchRule, collection.SORT_ORDER_CANONICAL, collection.TREE_INORDER, True, 1, True)
  689.         while not match:
  690.             if len(results) == 0:
  691.                 if wrapped or not wrap:
  692.                     break
  693.                 elif wrap:
  694.                     lastObj = self._findLastObject(document)
  695.                     secondLastObj = self._findPreviousObject(lastObj, document)
  696.                     results = collection.getMatchesFrom(secondLastObj, matchRule, collection.SORT_ORDER_CANONICAL, collection.TREE_INORDER, 1, True)
  697.                     wrapped = True
  698.                     if len(results) > 0:
  699.                         pass
  700.                     None if not predicate or predicate(results[0]) else predicate(results[0])
  701.                     results = collection.getMatchesTo(lastObj, matchRule, collection.SORT_ORDER_CANONICAL, collection.TREE_INORDER, True, 1, True)
  702.                 
  703.             not wrap
  704.             if len(results) > 0:
  705.                 if (results[0] in ancestors or predicate) and not predicate(results[0]):
  706.                     results = collection.getMatchesTo(results[0], matchRule, collection.SORT_ORDER_CANONICAL, collection.TREE_INORDER, True, 1, True)
  707.                 else:
  708.                     match = results[0]
  709.             not predicate(results[0])
  710.         return [
  711.             match,
  712.             wrapped]
  713.  
  714.     
  715.     def _findNextByMatchRule(self, collection, matchRule, wrap, currentObj, predicate = None):
  716.         '''Finds the next object using the given match rule as a pattern
  717.         to match or not match.
  718.  
  719.         Arguments:
  720.         -collection:  the accessible collection interface
  721.         -matchRule: the collections match rule to use
  722.         -wrap: if True and the bottom of the document is reached, move
  723.          to the top and keep looking.
  724.         -currentObj: the object from which the search should begin
  725.         -predicate: an optional predicate to further test if the item
  726.          found via collection is indeed a match.
  727.  
  728.         Returns: [obj, wrapped] where wrapped is a boolean reflecting
  729.         whether wrapping took place.
  730.         '''
  731.         if not currentObj:
  732.             pass
  733.         currentObj = self.getCurrentObject()
  734.         ancestors = []
  735.         (currentObj, offset) = self._script.getCaretContext()
  736.         obj = currentObj.parent
  737.         while obj:
  738.             ancestors.append(obj)
  739.             obj = obj.parent
  740.         match = None
  741.         wrapped = False
  742.         while not match:
  743.             results = collection.getMatchesFrom(currentObj, matchRule, collection.SORT_ORDER_CANONICAL, collection.TREE_INORDER, 1, True)
  744.             if len(results) > 0 and results[0] not in ancestors:
  745.                 currentObj = results[0]
  746.                 if not predicate or predicate(currentObj):
  747.                     match = currentObj
  748.                 
  749.             predicate(currentObj)
  750.             if wrap and not wrapped:
  751.                 wrapped = True
  752.                 ancestors = [
  753.                     currentObj]
  754.                 currentObj = self._getDocument()
  755.                 continue
  756.             break
  757.         return [
  758.             match,
  759.             wrapped]
  760.  
  761.     
  762.     def _findPrevByPredicate(self, pred, wrap, currentObj = None, arg = None):
  763.         '''Finds the caret offset at the beginning of the previous object
  764.         using the given predicate as a pattern to match.
  765.  
  766.         Arguments:
  767.         -pred: a python callable that takes an accessible argument and
  768.                returns true/false based on some match criteria
  769.         -wrap: if True and the top of the document is reached, move
  770.                to the bottom and keep looking.
  771.         -currentObj: the object from which the search should begin
  772.         -arg:  an additional value to be passed to the predicate
  773.  
  774.         Returns: [obj, wrapped] where wrapped is a boolean reflecting
  775.         whether wrapping took place.
  776.         '''
  777.         if not currentObj:
  778.             pass
  779.         currentObj = self.getCurrentObject()
  780.         document = self._getDocument()
  781.         if self._script.isSameObject(currentObj, document):
  782.             currentObj = self._findNextObject(currentObj, document)
  783.         
  784.         ancestors = []
  785.         nestableRoles = [
  786.             pyatspi.ROLE_LIST,
  787.             pyatspi.ROLE_TABLE]
  788.         obj = currentObj.parent
  789.         while obj:
  790.             ancestors.append(obj)
  791.             obj = obj.parent
  792.         obj = self._findPreviousObject(currentObj, document)
  793.         wrapped = obj is None
  794.         match = None
  795.         if wrapped:
  796.             obj = self._findLastObject(document)
  797.         
  798.         while obj and not match:
  799.             if obj != currentObj.parent and currentObj.parent.getRole() == obj.getRole():
  800.                 pass
  801.             isNested = obj.getRole() in nestableRoles
  802.             if (obj not in ancestors or isNested) and pred(obj):
  803.                 if wrapped and self._script.isSameObject(currentObj, obj):
  804.                     break
  805.                 else:
  806.                     match = obj
  807.             self._script.isSameObject(currentObj, obj)
  808.             obj = self._findPreviousObject(obj, document)
  809.             if not obj and wrap and not wrapped:
  810.                 obj = self._findLastObject(document)
  811.                 wrapped = True
  812.                 continue
  813.         return [
  814.             match,
  815.             wrapped]
  816.  
  817.     
  818.     def _findNextByPredicate(self, pred, wrap, currentObj = None, arg = None):
  819.         '''Finds the caret offset at the beginning of the next object
  820.         using the given predicate as a pattern to match or not match.
  821.  
  822.         Arguments:
  823.         -pred: a python callable that takes an accessible argument and
  824.                returns true/false based on some match criteria
  825.         -wrap: if True and the bottom of the document is reached, move
  826.                to the top and keep looking.
  827.         -currentObj: the object from which the search should begin
  828.         -arg:  an additional value to be passed to the predicate
  829.  
  830.         Returns: [obj, wrapped] where wrapped is a boolean reflecting
  831.         whether wrapping took place.
  832.         '''
  833.         if not currentObj:
  834.             pass
  835.         currentObj = self.getCurrentObject()
  836.         ancestors = []
  837.         obj = currentObj.parent
  838.         while obj:
  839.             ancestors.append(obj)
  840.             obj = obj.parent
  841.         document = self._getDocument()
  842.         obj = self._findNextObject(currentObj, document)
  843.         wrapped = obj is None
  844.         match = None
  845.         if wrapped:
  846.             (obj, offset) = self._getCaretPosition(document)
  847.         
  848.         while obj and not match:
  849.             if obj not in ancestors and pred(obj, arg):
  850.                 if wrapped and self._script.isSameObject(currentObj, obj):
  851.                     break
  852.                 else:
  853.                     match = obj
  854.             self._script.isSameObject(currentObj, obj)
  855.             obj = self._findNextObject(obj, document)
  856.             if not obj and wrap and not wrapped:
  857.                 (obj, offset) = self._getCaretPosition(document)
  858.                 wrapped = True
  859.                 continue
  860.         return [
  861.             match,
  862.             wrapped]
  863.  
  864.     
  865.     def _findPreviousObject(self, obj, stopAncestor):
  866.         """Finds the object prior to this one, where the tree we're
  867.         dealing with is a DOM and 'prior' means the previous object
  868.         in a linear presentation sense.
  869.  
  870.         Arguments:
  871.         -obj: the object where to start.
  872.         -stopAncestor: the ancestor at which the search should stop
  873.         """
  874.         prevObj = None
  875.         index = obj.getIndexInParent() - 1
  876.         if index >= 0:
  877.             prevObj = obj.parent[index]
  878.             if prevObj.childCount:
  879.                 prevObj = prevObj[prevObj.childCount - 1]
  880.             
  881.         elif not self._script.isSameObject(obj.parent, stopAncestor):
  882.             prevObj = obj.parent
  883.         
  884.         return prevObj
  885.  
  886.     
  887.     def _findNextObject(self, obj, stopAncestor):
  888.         """Finds the object after to this one, where the tree we're
  889.         dealing with is a DOM and 'next' means the next object
  890.         in a linear presentation sense.
  891.  
  892.         Arguments:
  893.         -obj: the object where to start.
  894.         -stopAncestor: the ancestor at which the search should stop
  895.         """
  896.         nextObj = None
  897.         if obj and obj.childCount:
  898.             nextObj = obj[0]
  899.         
  900.         while obj and obj.parent != obj and not nextObj:
  901.             index = obj.getIndexInParent() + 1
  902.             if index < index:
  903.                 pass
  904.             elif index < obj.parent.childCount:
  905.                 nextObj = obj.parent[index]
  906.                 continue
  907.             if not self._script.isSameObject(obj.parent, stopAncestor):
  908.                 obj = obj.parent
  909.                 continue
  910.             break
  911.         return nextObj
  912.  
  913.     
  914.     def _findLastObject(self, ancestor):
  915.         '''Returns the last object in ancestor.
  916.  
  917.         Arguments:
  918.         - ancestor: the accessible object whose last (child) object
  919.           is sought.
  920.         '''
  921.         if not ancestor or not (ancestor.childCount):
  922.             return ancestor
  923.         lastChild = ancestor[ancestor.childCount - 1]
  924.         while lastChild:
  925.             lastObj = self._findNextObject(lastChild, ancestor)
  926.             if lastObj:
  927.                 lastChild = lastObj
  928.                 continue
  929.             not (ancestor.childCount)
  930.             break
  931.         return lastChild
  932.  
  933.     
  934.     def _getDocument(self):
  935.         '''Returns the document or other object in which the object of
  936.         interest is contained.
  937.         '''
  938.         obj = self.getCurrentObject()
  939.         lastTextObj = obj
  940.         while obj and obj.getRole() != pyatspi.ROLE_FRAME:
  941.             
  942.             try:
  943.                 obj.queryText()
  944.             except:
  945.                 pass
  946.  
  947.             lastTextObj = obj
  948.             obj = obj.parent
  949.         return lastTextObj
  950.  
  951.     
  952.     def _isInDocument(self, obj):
  953.         '''Returns True if the accessible object obj is inside of
  954.         the document.
  955.  
  956.         Arguments:
  957.         -obj: the accessible object of interest.
  958.         '''
  959.         document = self._getDocument()
  960.         while obj and obj.parent:
  961.             if self._script.isSameObject(obj.parent, document):
  962.                 return True
  963.             obj = obj.parent
  964.             continue
  965.             self._script.isSameObject(obj.parent, document)
  966.         return False
  967.  
  968.     
  969.     def _isUselessObject(self, obj):
  970.         """Returns True if the accessible object obj is an object
  971.         that doesn't have any meaning associated with it. Individual
  972.         scripts should override this method as needed.  Gecko does.
  973.  
  974.         Arguments:
  975.         - obj: the accessible object of interest.
  976.         """
  977.         return False
  978.  
  979.     
  980.     def _getTableCaption(self, obj):
  981.         '''Returns a string which contains the table caption, or
  982.         None if a caption could not be found.
  983.  
  984.         Arguments:
  985.         - obj: the accessible table whose caption we want.
  986.         '''
  987.         caption = obj.queryTable().caption
  988.         
  989.         try:
  990.             caption.queryText()
  991.         except:
  992.             return None
  993.  
  994.         return self._script.getDisplayedText(caption)
  995.  
  996.     
  997.     def _getTableDescription(self, obj):
  998.         '''Returns a string which describes the table.'''
  999.         nonUniformString = ''
  1000.         nonUniform = self._isNonUniformTable(obj)
  1001.         if nonUniform:
  1002.             nonUniformString = _('Non-uniform') + ' '
  1003.         
  1004.         table = obj.queryTable()
  1005.         nRows = table.nRows
  1006.         nColumns = table.nColumns
  1007.         rowString = ngettext('Table with %d row', 'Table with %d rows', nRows) % nRows
  1008.         colString = ngettext('%d column', '%d columns', nColumns) % nColumns
  1009.         return nonUniformString + rowString + ' ' + colString
  1010.  
  1011.     
  1012.     def _isNonUniformTable(self, obj):
  1013.         '''Returns True if the obj is a non-uniform table (i.e. a table
  1014.         where at least one cell spans multiple rows and/or columns).
  1015.  
  1016.         Arguments:
  1017.         - obj: the table to examine
  1018.         '''
  1019.         
  1020.         try:
  1021.             table = obj.queryTable()
  1022.         except:
  1023.             pass
  1024.  
  1025.         for i in xrange(obj.childCount):
  1026.             (isCell, row, col, rowExtents, colExtents, isSelected) = table.getRowColumnExtentsAtIndex(i)
  1027.             if rowExtents > 1 or colExtents > 1:
  1028.                 return True
  1029.         
  1030.         return False
  1031.  
  1032.     
  1033.     def getCellForObj(self, obj):
  1034.         '''Looks for a table cell in the ancestry of obj, if obj is not a
  1035.         table cell.
  1036.  
  1037.         Arguments:
  1038.         - obj: the accessible object of interest.
  1039.         '''
  1040.         if obj and obj.getRole() != pyatspi.ROLE_TABLE_CELL:
  1041.             document = self._getDocument()
  1042.             obj = self._script.getAncestor(obj, [
  1043.                 pyatspi.ROLE_TABLE_CELL], [
  1044.                 document.getRole()])
  1045.         
  1046.         return obj
  1047.  
  1048.     
  1049.     def getTableForCell(self, obj):
  1050.         '''Looks for a table in the ancestry of obj, if obj is not a table.
  1051.  
  1052.         Arguments:
  1053.         - obj: the accessible object of interest.
  1054.         '''
  1055.         if obj and obj.getRole() != pyatspi.ROLE_TABLE:
  1056.             document = self._getDocument()
  1057.             obj = self._script.getAncestor(obj, [
  1058.                 pyatspi.ROLE_TABLE], [
  1059.                 document.getRole()])
  1060.         
  1061.         return obj
  1062.  
  1063.     
  1064.     def _isBlankCell(self, obj):
  1065.         '''Returns True if the table cell is empty or consists of whitespace.
  1066.  
  1067.         Arguments:
  1068.         - obj: the accessible table cell to examime
  1069.         '''
  1070.         text = self._script.getDisplayedText(obj)
  1071.         if text and len(text.strip()) and text != obj.name:
  1072.             return False
  1073.         for child in obj:
  1074.             text = self._script.getDisplayedText(child)
  1075.             if text or len(text.strip()) or child.getRole() == pyatspi.ROLE_LINK:
  1076.                 return False
  1077.         
  1078.         return True
  1079.  
  1080.     
  1081.     def _getCellText(self, obj):
  1082.         '''Looks at the table cell and tries to get its text.
  1083.  
  1084.         Arguments:
  1085.         - obj: the accessible table cell to examime
  1086.         '''
  1087.         text = ''
  1088.         if obj and not (obj.childCount):
  1089.             text = self._script.getDisplayedText(obj)
  1090.         else:
  1091.             for child in obj:
  1092.                 childText = self._script.getDisplayedText(child)
  1093.                 text = self._script.appendString(text, childText)
  1094.             
  1095.         return text
  1096.  
  1097.     
  1098.     def _presentCellHeaders(self, cell, oldCellInfo):
  1099.         '''Speaks the headers of the accessible table cell, cell.
  1100.  
  1101.         Arguments:
  1102.         - cell: the accessible table cell whose headers we wish to
  1103.           present.
  1104.         - oldCellInfo: [rowDiff, colDiff, oldRowHeaders, oldColHeaders]
  1105.         '''
  1106.         if not cell or not oldCellInfo:
  1107.             return None
  1108.         (rowDiff, colDiff, oldRowHeaders, oldColHeaders) = oldCellInfo
  1109.         if not oldRowHeaders or oldColHeaders:
  1110.             return None
  1111.         if rowDiff and not self._isInHeaderRow(cell):
  1112.             rowHeaders = self._getRowHeaders(cell)
  1113.             for header in rowHeaders:
  1114.                 if header not in oldRowHeaders:
  1115.                     text = self._getCellText(header)
  1116.                     speech.speak(text)
  1117.                     continue
  1118.                 oldColHeaders
  1119.             
  1120.         
  1121.         if colDiff and not self._isInHeaderColumn(cell):
  1122.             colHeaders = self._getColumnHeaders(cell)
  1123.             for header in colHeaders:
  1124.                 if header not in oldColHeaders:
  1125.                     text = self._getCellText(header)
  1126.                     speech.speak(text)
  1127.                     continue
  1128.             
  1129.         
  1130.  
  1131.     
  1132.     def _getCellSpanInfo(self, obj):
  1133.         '''Returns a string reflecting the number of rows and/or columns
  1134.         spanned by a table cell when multiple rows and/or columns are
  1135.         spanned.
  1136.  
  1137.         Arguments:
  1138.         - obj: the accessible table cell whose cell span we want.
  1139.         '''
  1140.         if not obj or obj.getRole() != pyatspi.ROLE_TABLE_CELL:
  1141.             return None
  1142.         (row, col) = self.getCellCoordinates(obj)
  1143.         table = obj.parent.queryTable()
  1144.         rowspan = table.getRowExtentAt(row, col)
  1145.         colspan = table.getColumnExtentAt(row, col)
  1146.         spanString = ''
  1147.         if colspan > 1 and rowspan > 1:
  1148.             spanString = _('Cell spans %d rows and %d columns') % (rowspan, colspan)
  1149.         elif colspan > 1:
  1150.             spanString = _('Cell spans %d columns') % colspan
  1151.         elif rowspan > 1:
  1152.             spanString = _('Cell spans %d rows') % rowspan
  1153.         
  1154.         return spanString
  1155.  
  1156.     
  1157.     def getCellCoordinates(self, obj):
  1158.         '''Returns the [row, col] of a ROLE_TABLE_CELL or [-1, -1]
  1159.         if the coordinates cannot be found.
  1160.  
  1161.         Arguments:
  1162.         - obj: the accessible table cell whose coordinates we want.
  1163.         '''
  1164.         obj = self.getCellForObj(obj)
  1165.         parent = self.getTableForCell(obj)
  1166.         
  1167.         try:
  1168.             table = parent.queryTable()
  1169.         except:
  1170.             pass
  1171.  
  1172.         (lastRow, lastCol) = self.lastTableCell
  1173.         lastKnownCell = table.getAccessibleAt(lastRow, lastCol)
  1174.         if self._script.isSameObject(lastKnownCell, obj):
  1175.             return [
  1176.                 lastRow,
  1177.                 lastCol]
  1178.         index = self._script.getCellIndex(obj)
  1179.         thisRow = table.getRowAtIndex(index)
  1180.         thisCol = table.getColumnAtIndex(index)
  1181.         return [
  1182.             thisRow,
  1183.             thisCol]
  1184.         return [
  1185.             -1,
  1186.             -1]
  1187.  
  1188.     
  1189.     def _getRowHeaders(self, obj):
  1190.         '''Returns a list of table cells that serve as a row header for
  1191.         the specified TABLE_CELL.
  1192.  
  1193.         Arguments:
  1194.         - obj: the accessible table cell whose header(s) we want.
  1195.         '''
  1196.         rowHeaders = []
  1197.         if not obj:
  1198.             return rowHeaders
  1199.         
  1200.         try:
  1201.             table = obj.parent.queryTable()
  1202.         except:
  1203.             obj
  1204.  
  1205.         (row, col) = self.getCellCoordinates(obj)
  1206.         header = table.getRowHeader(row)
  1207.         if header:
  1208.             rowHeaders.append(header)
  1209.         else:
  1210.             rowspan = table.getRowExtentAt(row, col)
  1211.             for r in range(row, row + rowspan):
  1212.                 for c in range(0, col):
  1213.                     cell = table.getAccessibleAt(r, c)
  1214.                     if self._isHeader(cell) and cell not in rowHeaders:
  1215.                         rowHeaders.append(cell)
  1216.                         continue
  1217.                 
  1218.             
  1219.         return rowHeaders
  1220.  
  1221.     
  1222.     def _getColumnHeaders(self, obj):
  1223.         '''Returns a list of table cells that serve as a column header for
  1224.         the specified TABLE_CELL.
  1225.  
  1226.         Arguments:
  1227.         - obj: the accessible table cell whose header(s) we want.
  1228.         '''
  1229.         columnHeaders = []
  1230.         if not obj:
  1231.             return columnHeaders
  1232.         
  1233.         try:
  1234.             table = obj.parent.queryTable()
  1235.         except:
  1236.             obj
  1237.  
  1238.         (row, col) = self.getCellCoordinates(obj)
  1239.         header = table.getColumnHeader(col)
  1240.         if header:
  1241.             columnHeaders.append(header)
  1242.         else:
  1243.             colspan = table.getColumnExtentAt(row, col)
  1244.             for c in range(col, col + colspan):
  1245.                 for r in range(0, row):
  1246.                     cell = table.getAccessibleAt(r, c)
  1247.                     if self._isHeader(cell) and cell not in columnHeaders:
  1248.                         columnHeaders.append(cell)
  1249.                         continue
  1250.                 
  1251.             
  1252.         return columnHeaders
  1253.  
  1254.     
  1255.     def _isInHeaderRow(self, obj):
  1256.         '''Returns True if all of the cells in the same row as this cell are
  1257.         headers.
  1258.  
  1259.         Arguments:
  1260.         - obj: the accessible table cell whose row is to be examined.
  1261.         '''
  1262.         if obj and obj.getRole() == pyatspi.ROLE_TABLE_CELL:
  1263.             table = obj.parent.queryTable()
  1264.             index = self._script.getCellIndex(obj)
  1265.             row = table.getRowAtIndex(index)
  1266.             for col in xrange(table.nColumns):
  1267.                 cell = table.getAccessibleAt(row, col)
  1268.                 if not self._isHeader(cell):
  1269.                     return False
  1270.             
  1271.         
  1272.         return True
  1273.  
  1274.     
  1275.     def _isInHeaderColumn(self, obj):
  1276.         '''Returns True if all of the cells in the same column as this cell
  1277.         are headers.
  1278.  
  1279.         Arguments:
  1280.         - obj: the accessible table cell whose column is to be examined.
  1281.         '''
  1282.         if obj and obj.getRole() == pyatspi.ROLE_TABLE_CELL:
  1283.             table = obj.parent.queryTable()
  1284.             index = self._script.getCellIndex(obj)
  1285.             col = table.getColumnAtIndex(index)
  1286.             for row in xrange(table.nRows):
  1287.                 cell = table.getAccessibleAt(row, col)
  1288.                 if not self._isHeader(cell):
  1289.                     return False
  1290.             
  1291.         
  1292.         return True
  1293.  
  1294.     
  1295.     def _isHeader(self, obj):
  1296.         '''Returns True if the table cell is a header.
  1297.  
  1298.         Arguments:
  1299.         - obj: the accessible table cell to examine.
  1300.         '''
  1301.         if not obj:
  1302.             return False
  1303.         if obj.getRole() in [
  1304.             pyatspi.ROLE_TABLE_COLUMN_HEADER,
  1305.             pyatspi.ROLE_TABLE_ROW_HEADER]:
  1306.             return True
  1307.         attributes = obj.getAttributes()
  1308.  
  1309.     
  1310.     def _getHeadingLevel(self, obj):
  1311.         '''Determines the heading level of the given object.  A value
  1312.         of 0 means there is no heading level.
  1313.  
  1314.         Arguments:
  1315.         - obj: the accessible whose heading level we want.
  1316.         '''
  1317.         level = 0
  1318.         if obj is None:
  1319.             return level
  1320.         if obj.getRole() == pyatspi.ROLE_HEADING:
  1321.             attributes = obj.getAttributes()
  1322.             if attributes is None:
  1323.                 return level
  1324.             for attribute in attributes:
  1325.                 if attribute.startswith('level:'):
  1326.                     level = int(attribute.split(':')[1])
  1327.                     break
  1328.                     continue
  1329.                 attributes is None
  1330.             
  1331.         
  1332.         return level
  1333.  
  1334.     
  1335.     def _getCaretPosition(self, obj):
  1336.         """Returns the [obj, characterOffset] where the caret should be
  1337.         positioned. For most scripts, the object should not change and
  1338.         the offset should be 0.  That's not always the case with Gecko.
  1339.  
  1340.         Arguments:
  1341.         - obj: the accessible object in which the caret should be
  1342.           positioned.
  1343.         """
  1344.         return [
  1345.             obj,
  1346.             0]
  1347.  
  1348.     
  1349.     def _setCaretPosition(self, obj, characterOffset):
  1350.         '''Sets the caret at the specified offset within obj.
  1351.  
  1352.         Arguments:
  1353.         - obj: the accessible object in which the caret should be
  1354.           positioned.
  1355.         - characterOffset: the offset at which to position the caret.
  1356.         '''
  1357.         
  1358.         try:
  1359.             text = obj.queryText()
  1360.             text.setCaretOffset(characterOffset)
  1361.         except NotImplementedError:
  1362.             
  1363.             try:
  1364.                 obj.queryComponent().grabFocus()
  1365.             debug.printException(debug.LEVEL_SEVERE)
  1366.  
  1367.         except:
  1368.             debug.printException(debug.LEVEL_SEVERE)
  1369.  
  1370.         orca.setLocusOfFocus(None, obj, False)
  1371.  
  1372.     
  1373.     def _presentLine(self, obj, offset):
  1374.         '''Presents the first line of the object to the user.
  1375.  
  1376.         Arguments:
  1377.         - obj: the accessible object to be presented.
  1378.         - offset: the character offset within obj.
  1379.         '''
  1380.         self._script.updateBraille(obj)
  1381.         self._script.sayLine(obj)
  1382.  
  1383.     
  1384.     def _presentObject(self, obj, offset):
  1385.         '''Presents the entire object to the user.
  1386.  
  1387.         Arguments:
  1388.         - obj: the accessible object to be presented.
  1389.         - offset: the character offset within obj.
  1390.         '''
  1391.         self._script.updateBraille(obj)
  1392.         utterances = []
  1393.         strings = self._script.speechGenerator.getSpeech(obj, False)
  1394.         for string in strings:
  1395.             voice = self._getVoice(obj, string)
  1396.             speech.speak(string, voice)
  1397.         
  1398.  
  1399.     
  1400.     def _getVoice(self, obj, string):
  1401.         '''Returns the voice to speak anything for the given obj.
  1402.  
  1403.         Arguments:
  1404.         - obj: the accessible object to be presented.
  1405.         - string: the string to be spoken for obj.
  1406.         '''
  1407.         voices = self._script.voices
  1408.         if obj.getRole() == pyatspi.ROLE_LINK:
  1409.             voice = voices[settings.HYPERLINK_VOICE]
  1410.         elif string and string.isupper() and string.strip().isalpha():
  1411.             voice = voices[settings.UPPERCASE_VOICE]
  1412.         else:
  1413.             voice = voices[settings.DEFAULT_VOICE]
  1414.         return voice
  1415.  
  1416.     
  1417.     def _anchorBindings(self):
  1418.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1419.         lists for navigating amongst anchors.
  1420.         '''
  1421.         bindings = { }
  1422.         prevDesc = _('Goes to previous anchor.')
  1423.         bindings['previous'] = [
  1424.             '',
  1425.             settings.NO_MODIFIER_MASK,
  1426.             prevDesc]
  1427.         nextDesc = _('Goes to next anchor.')
  1428.         bindings['next'] = [
  1429.             '',
  1430.             settings.NO_MODIFIER_MASK,
  1431.             nextDesc]
  1432.         return bindings
  1433.  
  1434.     
  1435.     def _anchorCriteria(self, collection, arg = None):
  1436.         '''Returns the MatchCriteria to be used for locating anchors
  1437.         by collection.
  1438.  
  1439.         Arguments:
  1440.         - collection: the collection interface for the document
  1441.         - arg: an optional argument which may need to be included in
  1442.           the criteria (e.g. the level of a heading).
  1443.         '''
  1444.         role = [
  1445.             pyatspi.ROLE_LINK]
  1446.         state = [
  1447.             pyatspi.STATE_FOCUSABLE]
  1448.         stateMatch = collection.MATCH_NONE
  1449.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  1450.  
  1451.     
  1452.     def _anchorPredicate(self, obj, arg = None):
  1453.         '''The predicate to be used for verifying that the object
  1454.         obj is an anchor.
  1455.  
  1456.         Arguments:
  1457.         - obj: the accessible object under consideration.
  1458.         - arg: an optional argument which may need to be included in
  1459.           the criteria (e.g. the level of a heading).
  1460.         '''
  1461.         isMatch = False
  1462.         if obj and obj.getRole() == pyatspi.ROLE_LINK:
  1463.             state = obj.getState()
  1464.             isMatch = not state.contains(pyatspi.STATE_FOCUSABLE)
  1465.         
  1466.         return isMatch
  1467.  
  1468.     
  1469.     def _anchorPresentation(self, obj, arg = None):
  1470.         '''Presents the anchor or indicates that one was not found.
  1471.  
  1472.         Arguments:
  1473.         - obj: the accessible object under consideration.
  1474.         - arg: an optional argument which may need to be included in
  1475.           the criteria (e.g. the level of a heading).
  1476.         '''
  1477.         if obj:
  1478.             (obj, characterOffset) = self._getCaretPosition(obj)
  1479.             self._setCaretPosition(obj, characterOffset)
  1480.             self._presentObject(obj, characterOffset)
  1481.         else:
  1482.             speech.speak(_('No more anchors.'))
  1483.  
  1484.     
  1485.     def _blockquoteBindings(self):
  1486.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1487.         lists for navigating among blockquotes.
  1488.         '''
  1489.         bindings = { }
  1490.         prevDesc = _('Goes to previous blockquote.')
  1491.         bindings['previous'] = [
  1492.             'q',
  1493.             settings.SHIFT_MODIFIER_MASK,
  1494.             prevDesc]
  1495.         nextDesc = _('Goes to next blockquote.')
  1496.         bindings['next'] = [
  1497.             'q',
  1498.             settings.NO_MODIFIER_MASK,
  1499.             nextDesc]
  1500.         return bindings
  1501.  
  1502.     
  1503.     def _blockquoteCriteria(self, collection, arg = None):
  1504.         '''Returns the MatchCriteria to be used for locating blockquotes
  1505.         by collection.
  1506.  
  1507.         Arguments:
  1508.         - collection: the collection interface for the document
  1509.         - arg: an optional argument which may need to be included in
  1510.           the criteria (e.g. the level of a heading).
  1511.         '''
  1512.         attrs = [
  1513.             'tag:BLOCKQUOTE']
  1514.         return MatchCriteria(collection, objAttrs = attrs)
  1515.  
  1516.     
  1517.     def _blockquotePredicate(self, obj, arg = None):
  1518.         '''The predicate to be used for verifying that the object
  1519.         obj is a blockquote.
  1520.  
  1521.         Arguments:
  1522.         - obj: the accessible object under consideration.
  1523.         - arg: an optional argument which may need to be included in
  1524.           the criteria (e.g. the level of a heading).
  1525.         '''
  1526.         if not obj:
  1527.             return False
  1528.         attributes = obj.getAttributes()
  1529.         return False
  1530.  
  1531.     
  1532.     def _blockquotePresentation(self, obj, arg = None):
  1533.         '''Presents the blockquote or indicates that one was not found.
  1534.  
  1535.         Arguments:
  1536.         - obj: the accessible object under consideration.
  1537.         - arg: an optional argument which may need to be included in
  1538.           the criteria (e.g. the level of a heading).
  1539.         '''
  1540.         if obj:
  1541.             (obj, characterOffset) = self._getCaretPosition(obj)
  1542.             self._setCaretPosition(obj, characterOffset)
  1543.             self._presentLine(obj, characterOffset)
  1544.         else:
  1545.             speech.speak(_('No more blockquotes.'))
  1546.  
  1547.     
  1548.     def _buttonBindings(self):
  1549.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1550.         lists for navigating amongst buttons.
  1551.         '''
  1552.         bindings = { }
  1553.         prevDesc = _('Goes to previous button.')
  1554.         bindings['previous'] = [
  1555.             '',
  1556.             settings.NO_MODIFIER_MASK,
  1557.             prevDesc]
  1558.         nextDesc = _('Goes to next button.')
  1559.         bindings['next'] = [
  1560.             '',
  1561.             settings.NO_MODIFIER_MASK,
  1562.             nextDesc]
  1563.         return bindings
  1564.  
  1565.     
  1566.     def _buttonCriteria(self, collection, arg = None):
  1567.         '''Returns the MatchCriteria to be used for locating buttons
  1568.         by collection.
  1569.  
  1570.         Arguments:
  1571.         - collection: the collection interface for the document
  1572.         - arg: an optional argument which may need to be included in
  1573.           the criteria (e.g. the level of a heading).
  1574.         '''
  1575.         role = [
  1576.             pyatspi.ROLE_PUSH_BUTTON]
  1577.         state = [
  1578.             pyatspi.STATE_FOCUSABLE,
  1579.             pyatspi.STATE_SENSITIVE]
  1580.         stateMatch = collection.MATCH_ALL
  1581.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  1582.  
  1583.     
  1584.     def _buttonPredicate(self, obj, arg = None):
  1585.         '''The predicate to be used for verifying that the object
  1586.         obj is a button.
  1587.  
  1588.         Arguments:
  1589.         - obj: the accessible object under consideration.
  1590.         - arg: an optional argument which may need to be included in
  1591.           the criteria (e.g. the level of a heading).
  1592.         '''
  1593.         isMatch = False
  1594.         if obj and obj.getRole() == pyatspi.ROLE_PUSH_BUTTON:
  1595.             state = obj.getState()
  1596.             if state.contains(pyatspi.STATE_FOCUSABLE):
  1597.                 pass
  1598.             isMatch = state.contains(pyatspi.STATE_SENSITIVE)
  1599.         
  1600.         return isMatch
  1601.  
  1602.     
  1603.     def _buttonPresentation(self, obj, arg = None):
  1604.         '''Presents the button or indicates that one was not found.
  1605.  
  1606.         Arguments:
  1607.         - obj: the accessible object under consideration.
  1608.         - arg: an optional argument which may need to be included in
  1609.           the criteria (e.g. the level of a heading).
  1610.         '''
  1611.         if obj:
  1612.             obj.queryComponent().grabFocus()
  1613.         else:
  1614.             speech.speak(_('No more buttons.'))
  1615.  
  1616.     
  1617.     def _checkBoxBindings(self):
  1618.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1619.         lists for navigating amongst check boxes.
  1620.         '''
  1621.         bindings = { }
  1622.         prevDesc = _('Goes to previous check box.')
  1623.         bindings['previous'] = [
  1624.             '',
  1625.             settings.NO_MODIFIER_MASK,
  1626.             prevDesc]
  1627.         nextDesc = _('Goes to next check box.')
  1628.         bindings['next'] = [
  1629.             '',
  1630.             settings.NO_MODIFIER_MASK,
  1631.             nextDesc]
  1632.         return bindings
  1633.  
  1634.     
  1635.     def _checkBoxCriteria(self, collection, arg = None):
  1636.         '''Returns the MatchCriteria to be used for locating check boxes
  1637.         by collection.
  1638.  
  1639.         Arguments:
  1640.         - collection: the collection interface for the document
  1641.         - arg: an optional argument which may need to be included in
  1642.           the criteria (e.g. the level of a heading).
  1643.         '''
  1644.         role = [
  1645.             pyatspi.ROLE_CHECK_BOX]
  1646.         state = [
  1647.             pyatspi.STATE_FOCUSABLE,
  1648.             pyatspi.STATE_SENSITIVE]
  1649.         stateMatch = collection.MATCH_ALL
  1650.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  1651.  
  1652.     
  1653.     def _checkBoxPredicate(self, obj, arg = None):
  1654.         '''The predicate to be used for verifying that the object
  1655.         obj is a check box.
  1656.  
  1657.         Arguments:
  1658.         - obj: the accessible object under consideration.
  1659.         - arg: an optional argument which may need to be included in
  1660.           the criteria (e.g. the level of a heading).
  1661.         '''
  1662.         isMatch = False
  1663.         if obj and obj.getRole() == pyatspi.ROLE_CHECK_BOX:
  1664.             state = obj.getState()
  1665.             if state.contains(pyatspi.STATE_FOCUSABLE):
  1666.                 pass
  1667.             isMatch = state.contains(pyatspi.STATE_SENSITIVE)
  1668.         
  1669.         return isMatch
  1670.  
  1671.     
  1672.     def _checkBoxPresentation(self, obj, arg = None):
  1673.         '''Presents the check box or indicates that one was not found.
  1674.  
  1675.         Arguments:
  1676.         - obj: the accessible object under consideration.
  1677.         - arg: an optional argument which may need to be included in
  1678.           the criteria (e.g. the level of a heading).
  1679.         '''
  1680.         if obj:
  1681.             obj.queryComponent().grabFocus()
  1682.         else:
  1683.             speech.speak(_('No more check boxes.'))
  1684.  
  1685.     
  1686.     def _chunkBindings(self):
  1687.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1688.         lists for navigating amongst chunks/large objects.
  1689.         '''
  1690.         bindings = { }
  1691.         prevDesc = _('Goes to previous large object.')
  1692.         bindings['previous'] = [
  1693.             'o',
  1694.             settings.SHIFT_MODIFIER_MASK,
  1695.             prevDesc]
  1696.         nextDesc = _('Goes to next large object.')
  1697.         bindings['next'] = [
  1698.             'o',
  1699.             settings.NO_MODIFIER_MASK,
  1700.             nextDesc]
  1701.         return bindings
  1702.  
  1703.     
  1704.     def _chunkCriteria(self, collection, arg = None):
  1705.         '''Returns the MatchCriteria to be used for locating chunks/
  1706.         large objects by collection.
  1707.  
  1708.         Arguments:
  1709.         - collection: the collection interface for the document
  1710.         - arg: an optional argument which may need to be included in
  1711.           the criteria (e.g. the level of a heading).
  1712.         '''
  1713.         role = self.OBJECT_ROLES
  1714.         roleMatch = collection.MATCH_ANY
  1715.         return MatchCriteria(collection, roles = role, matchRoles = roleMatch, applyPredicate = True)
  1716.  
  1717.     
  1718.     def _chunkPredicate(self, obj, arg = None):
  1719.         '''The predicate to be used for verifying that the object
  1720.         obj is a chunk.
  1721.  
  1722.         Arguments:
  1723.         - obj: the accessible object under consideration.
  1724.         - arg: an optional argument which may need to be included in
  1725.           the criteria (e.g. the level of a heading).
  1726.         '''
  1727.         isMatch = False
  1728.         if obj and obj.getRole() in self.OBJECT_ROLES:
  1729.             
  1730.             try:
  1731.                 text = obj.queryText()
  1732.                 characterCount = text.characterCount
  1733.             except:
  1734.                 characterCount = 0
  1735.  
  1736.             if characterCount > settings.largeObjectTextLength and not self._isUselessObject(obj):
  1737.                 isMatch = True
  1738.             
  1739.         
  1740.         return isMatch
  1741.  
  1742.     
  1743.     def _chunkPresentation(self, obj, arg = None):
  1744.         '''Presents the chunk or indicates that one was not found.
  1745.  
  1746.         Arguments:
  1747.         - obj: the accessible object under consideration.
  1748.         - arg: an optional argument which may need to be included in
  1749.           the criteria (e.g. the level of a heading).
  1750.         '''
  1751.         if obj:
  1752.             (newObj, characterOffset) = self._getCaretPosition(obj)
  1753.             self._setCaretPosition(newObj, characterOffset)
  1754.             self._presentObject(obj, 0)
  1755.         else:
  1756.             speech.speak(_('No more large objects.'))
  1757.  
  1758.     
  1759.     def _comboBoxBindings(self):
  1760.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1761.         lists for navigating amongst combo boxes.
  1762.         '''
  1763.         bindings = { }
  1764.         prevDesc = _('Goes to previous combo box.')
  1765.         bindings['previous'] = [
  1766.             '',
  1767.             settings.NO_MODIFIER_MASK,
  1768.             prevDesc]
  1769.         nextDesc = _('Goes to next combo box.')
  1770.         bindings['next'] = [
  1771.             '',
  1772.             settings.NO_MODIFIER_MASK,
  1773.             nextDesc]
  1774.         return bindings
  1775.  
  1776.     
  1777.     def _comboBoxCriteria(self, collection, arg = None):
  1778.         '''Returns the MatchCriteria to be used for locating combo boxes
  1779.         by collection.
  1780.  
  1781.         Arguments:
  1782.         - collection: the collection interface for the document
  1783.         - arg: an optional argument which may need to be included in
  1784.           the criteria (e.g. the level of a heading).
  1785.         '''
  1786.         role = [
  1787.             pyatspi.ROLE_COMBO_BOX]
  1788.         state = [
  1789.             pyatspi.STATE_FOCUSABLE,
  1790.             pyatspi.STATE_SENSITIVE]
  1791.         stateMatch = collection.MATCH_ALL
  1792.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  1793.  
  1794.     
  1795.     def _comboBoxPredicate(self, obj, arg = None):
  1796.         '''The predicate to be used for verifying that the object
  1797.         obj is a combo box.
  1798.  
  1799.         Arguments:
  1800.         - obj: the accessible object under consideration.
  1801.         - arg: an optional argument which may need to be included in
  1802.           the criteria (e.g. the level of a heading).
  1803.         '''
  1804.         isMatch = False
  1805.         if obj and obj.getRole() == pyatspi.ROLE_COMBO_BOX:
  1806.             state = obj.getState()
  1807.             if state.contains(pyatspi.STATE_FOCUSABLE):
  1808.                 pass
  1809.             isMatch = state.contains(pyatspi.STATE_SENSITIVE)
  1810.         
  1811.         return isMatch
  1812.  
  1813.     
  1814.     def _comboBoxPresentation(self, obj, arg = None):
  1815.         '''Presents the combo box or indicates that one was not found.
  1816.  
  1817.         Arguments:
  1818.         - obj: the accessible object under consideration.
  1819.         - arg: an optional argument which may need to be included in
  1820.           the criteria (e.g. the level of a heading).
  1821.         '''
  1822.         if obj:
  1823.             obj.queryComponent().grabFocus()
  1824.         else:
  1825.             speech.speak(_('No more combo boxes.'))
  1826.  
  1827.     
  1828.     def _entryBindings(self):
  1829.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1830.         lists for navigating amongst entries.
  1831.         '''
  1832.         bindings = { }
  1833.         prevDesc = _('Goes to previous entry.')
  1834.         bindings['previous'] = [
  1835.             '',
  1836.             settings.NO_MODIFIER_MASK,
  1837.             prevDesc]
  1838.         nextDesc = _('Goes to next entry.')
  1839.         bindings['next'] = [
  1840.             '',
  1841.             settings.NO_MODIFIER_MASK,
  1842.             nextDesc]
  1843.         return bindings
  1844.  
  1845.     
  1846.     def _entryCriteria(self, collection, arg = None):
  1847.         '''Returns the MatchCriteria to be used for locating entries
  1848.         by collection.
  1849.  
  1850.         Arguments:
  1851.         - collection: the collection interface for the document
  1852.         - arg: an optional argument which may need to be included in
  1853.           the criteria (e.g. the level of a heading).
  1854.         '''
  1855.         role = [
  1856.             pyatspi.ROLE_ENTRY,
  1857.             pyatspi.ROLE_PASSWORD_TEXT,
  1858.             pyatspi.ROLE_TEXT]
  1859.         roleMatch = collection.MATCH_ANY
  1860.         state = [
  1861.             pyatspi.STATE_FOCUSABLE,
  1862.             pyatspi.STATE_SENSITIVE,
  1863.             pyatspi.STATE_EDITABLE]
  1864.         stateMatch = collection.MATCH_ALL
  1865.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role, matchRoles = roleMatch)
  1866.  
  1867.     
  1868.     def _entryPredicate(self, obj, arg = None):
  1869.         '''The predicate to be used for verifying that the object
  1870.         obj is an entry.
  1871.  
  1872.         Arguments:
  1873.         - obj: the accessible object under consideration.
  1874.         - arg: an optional argument which may need to be included in
  1875.           the criteria (e.g. the level of a heading).
  1876.         '''
  1877.         isMatch = False
  1878.         if obj and obj.getRole() in [
  1879.             pyatspi.ROLE_ENTRY,
  1880.             pyatspi.ROLE_PASSWORD_TEXT,
  1881.             pyatspi.ROLE_TEXT]:
  1882.             state = obj.getState()
  1883.             if state.contains(pyatspi.STATE_FOCUSABLE) and state.contains(pyatspi.STATE_SENSITIVE):
  1884.                 pass
  1885.             isMatch = state.contains(pyatspi.STATE_EDITABLE)
  1886.         
  1887.         return isMatch
  1888.  
  1889.     
  1890.     def _entryPresentation(self, obj, arg = None):
  1891.         '''Presents the entry or indicates that one was not found.
  1892.  
  1893.         Arguments:
  1894.         - obj: the accessible object under consideration.
  1895.         - arg: an optional argument which may need to be included in
  1896.           the criteria (e.g. the level of a heading).
  1897.         '''
  1898.         if obj:
  1899.             obj.queryComponent().grabFocus()
  1900.         else:
  1901.             speech.speak(_('No more entries.'))
  1902.  
  1903.     
  1904.     def _formFieldBindings(self):
  1905.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1906.         lists for navigating amongst form fields.
  1907.         '''
  1908.         bindings = { }
  1909.         prevDesc = _('Goes to previous form field.')
  1910.         bindings['previous'] = [
  1911.             'Tab',
  1912.             settings.ORCA_SHIFT_MODIFIER_MASK,
  1913.             prevDesc]
  1914.         nextDesc = _('Goes to next form field.')
  1915.         bindings['next'] = [
  1916.             'Tab',
  1917.             settings.ORCA_MODIFIER_MASK,
  1918.             nextDesc]
  1919.         return bindings
  1920.  
  1921.     
  1922.     def _formFieldCriteria(self, collection, arg = None):
  1923.         '''Returns the MatchCriteria to be used for locating form fields
  1924.         by collection.
  1925.  
  1926.         Arguments:
  1927.         - collection: the collection interface for the document
  1928.         - arg: an optional argument which may need to be included in
  1929.           the criteria (e.g. the level of a heading).
  1930.         '''
  1931.         role = self.FORM_ROLES
  1932.         roleMatch = collection.MATCH_ANY
  1933.         state = [
  1934.             pyatspi.STATE_FOCUSABLE,
  1935.             pyatspi.STATE_SENSITIVE]
  1936.         stateMatch = collection.MATCH_ALL
  1937.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role, matchRoles = roleMatch)
  1938.  
  1939.     
  1940.     def _formFieldPredicate(self, obj, arg = None):
  1941.         '''The predicate to be used for verifying that the object
  1942.         obj is a form field.
  1943.  
  1944.         Arguments:
  1945.         - obj: the accessible object under consideration.
  1946.         - arg: an optional argument which may need to be included in
  1947.           the criteria (e.g. the level of a heading).
  1948.         '''
  1949.         isMatch = False
  1950.         if obj and obj.getRole() in self.FORM_ROLES:
  1951.             state = obj.getState()
  1952.             if state.contains(pyatspi.STATE_FOCUSABLE):
  1953.                 pass
  1954.             isMatch = state.contains(pyatspi.STATE_SENSITIVE)
  1955.         
  1956.         return isMatch
  1957.  
  1958.     
  1959.     def _formFieldPresentation(self, obj, arg = None):
  1960.         '''Presents the form field or indicates that one was not found.
  1961.  
  1962.         Arguments:
  1963.         - obj: the accessible object under consideration.
  1964.         - arg: an optional argument which may need to be included in
  1965.           the criteria (e.g. the level of a heading).
  1966.         '''
  1967.         if obj:
  1968.             if obj.getRole() in [
  1969.                 pyatspi.ROLE_LIST,
  1970.                 pyatspi.ROLE_COMBO_BOX]:
  1971.                 obj.queryComponent().grabFocus()
  1972.             else:
  1973.                 (obj, characterOffset) = self._getCaretPosition(obj)
  1974.                 self._setCaretPosition(obj, characterOffset)
  1975.                 self._presentObject(obj, characterOffset)
  1976.         else:
  1977.             speech.speak(_('No more form fields.'))
  1978.  
  1979.     
  1980.     def _headingBindings(self):
  1981.         '''Returns a dictionary of [keysymstring, modifiers, description]
  1982.         lists for navigating amongst headings.
  1983.         '''
  1984.         bindings = { }
  1985.         prevDesc = _('Goes to previous heading.')
  1986.         bindings['previous'] = [
  1987.             'h',
  1988.             settings.SHIFT_MODIFIER_MASK,
  1989.             prevDesc]
  1990.         nextDesc = _('Goes to next heading.')
  1991.         bindings['next'] = [
  1992.             'h',
  1993.             settings.NO_MODIFIER_MASK,
  1994.             nextDesc]
  1995.         prevAtLevelBindings = []
  1996.         nextAtLevelBindings = []
  1997.         (minLevel, maxLevel) = self._headingLevels()
  1998.         for i in range(minLevel, maxLevel + 1):
  1999.             prevDesc = _('Goes to previous heading at level %d.') % i
  2000.             prevAtLevelBindings.append([
  2001.                 str(i),
  2002.                 settings.SHIFT_MODIFIER_MASK,
  2003.                 prevDesc])
  2004.             nextDesc = _('Goes to next heading at level %d.') % i
  2005.             nextAtLevelBindings.append([
  2006.                 str(i),
  2007.                 settings.NO_MODIFIER_MASK,
  2008.                 nextDesc])
  2009.         
  2010.         bindings['previousAtLevel'] = prevAtLevelBindings
  2011.         bindings['nextAtLevel'] = nextAtLevelBindings
  2012.         return bindings
  2013.  
  2014.     
  2015.     def _headingLevels(self):
  2016.         '''Returns the [minimum heading level, maximum heading level]
  2017.         which should be navigable via structural navigation.
  2018.         '''
  2019.         return [
  2020.             1,
  2021.             6]
  2022.  
  2023.     
  2024.     def _headingCriteria(self, collection, arg = None):
  2025.         '''Returns the MatchCriteria to be used for locating headings
  2026.         by collection.
  2027.  
  2028.         Arguments:
  2029.         - collection: the collection interface for the document
  2030.         - arg: an optional argument which may need to be included in
  2031.           the criteria (e.g. the level of a heading).
  2032.         '''
  2033.         role = [
  2034.             pyatspi.ROLE_HEADING]
  2035.         attrs = []
  2036.         if arg:
  2037.             attrs.append('level:%d' % arg)
  2038.         
  2039.         return MatchCriteria(collection, roles = role, objAttrs = attrs)
  2040.  
  2041.     
  2042.     def _headingPredicate(self, obj, arg = None):
  2043.         '''The predicate to be used for verifying that the object
  2044.         obj is a heading.
  2045.  
  2046.         Arguments:
  2047.         - obj: the accessible object under consideration.
  2048.         - arg: an optional argument which may need to be included in
  2049.           the criteria (e.g. the level of a heading).
  2050.         '''
  2051.         isMatch = False
  2052.         if obj and obj.getRole() == pyatspi.ROLE_HEADING:
  2053.             if arg:
  2054.                 isMatch = arg == self._getHeadingLevel(obj)
  2055.             else:
  2056.                 isMatch = True
  2057.         
  2058.         return isMatch
  2059.  
  2060.     
  2061.     def _headingPresentation(self, obj, arg = None):
  2062.         '''Presents the heading or indicates that one was not found.
  2063.  
  2064.         Arguments:
  2065.         - obj: the accessible object under consideration.
  2066.         - arg: an optional argument which may need to be included in
  2067.           the criteria (e.g. the level of a heading).
  2068.         '''
  2069.         if obj:
  2070.             (obj, characterOffset) = self._getCaretPosition(obj)
  2071.             self._setCaretPosition(obj, characterOffset)
  2072.             self._presentObject(obj, characterOffset)
  2073.         elif not arg:
  2074.             speech.speak(_('No more headings.'))
  2075.         else:
  2076.             speech.speak(_('No more headings at level %d.') % arg)
  2077.  
  2078.     
  2079.     def _landmarkBindings(self):
  2080.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2081.         lists for navigating amongst landmarks.
  2082.         '''
  2083.         bindings = { }
  2084.         prevDesc = _('Goes to previous landmark.')
  2085.         bindings['previous'] = [
  2086.             'm',
  2087.             settings.SHIFT_MODIFIER_MASK,
  2088.             prevDesc]
  2089.         nextDesc = _('Goes to next landmark.')
  2090.         bindings['next'] = [
  2091.             'm',
  2092.             settings.NO_MODIFIER_MASK,
  2093.             nextDesc]
  2094.         return bindings
  2095.  
  2096.     
  2097.     def _landmarkCriteria(self, collection, arg = None):
  2098.         '''Returns the MatchCriteria to be used for locating landmarks
  2099.         by collection.
  2100.  
  2101.         Arguments:
  2102.         - collection: the collection interface for the document
  2103.         - arg: an optional argument which may need to be included in
  2104.           the criteria (e.g. the level of a heading).
  2105.         '''
  2106.         attrs = []
  2107.         for landmark in settings.ariaLandmarks:
  2108.             attrs.append('xml-roles:' + landmark)
  2109.         
  2110.         return MatchCriteria(collection, objAttrs = attrs)
  2111.  
  2112.     
  2113.     def _landmarkPredicate(self, obj, arg = None):
  2114.         '''The predicate to be used for verifying that the object
  2115.         obj is a landmark.
  2116.  
  2117.         Arguments:
  2118.         - obj: the accessible object under consideration.
  2119.         - arg: an optional argument which may need to be included in
  2120.           the criteria (e.g. the level of a heading).
  2121.         '''
  2122.         if obj is None:
  2123.             return False
  2124.         attrs = []([ attr.split(':', 1) for attr in obj.getAttributes() ])
  2125.         
  2126.         try:
  2127.             import sets
  2128.             if sets.Set(attrs['xml-roles']).intersection(sets.Set(settings.ariaLandmarks)):
  2129.                 return True
  2130.             return False
  2131.         except KeyError:
  2132.             []
  2133.             []
  2134.             dict
  2135.             return False
  2136.             obj is None
  2137.  
  2138.  
  2139.     
  2140.     def _landmarkPresentation(self, obj, arg = None):
  2141.         '''Presents the landmark or indicates that one was not found.
  2142.  
  2143.         Arguments:
  2144.         - obj: the accessible object under consideration.
  2145.         - arg: an optional argument which may need to be included in
  2146.           the criteria (e.g. the level of a heading).
  2147.         '''
  2148.         if obj:
  2149.             (obj, characterOffset) = self._getCaretPosition(obj)
  2150.             self._setCaretPosition(obj, characterOffset)
  2151.             self._presentObject(obj, characterOffset)
  2152.         else:
  2153.             speech.speak(_('No landmark found.'))
  2154.  
  2155.     
  2156.     def _listBindings(self):
  2157.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2158.         lists for navigating amongst (un)ordered lists.
  2159.         '''
  2160.         bindings = { }
  2161.         prevDesc = _('Goes to previous list.')
  2162.         bindings['previous'] = [
  2163.             'l',
  2164.             settings.SHIFT_MODIFIER_MASK,
  2165.             prevDesc]
  2166.         nextDesc = _('Goes to next list.')
  2167.         bindings['next'] = [
  2168.             'l',
  2169.             settings.NO_MODIFIER_MASK,
  2170.             nextDesc]
  2171.         return bindings
  2172.  
  2173.     
  2174.     def _listCriteria(self, collection, arg = None):
  2175.         '''Returns the MatchCriteria to be used for locating (un)ordered
  2176.         lists by collection.
  2177.  
  2178.         Arguments:
  2179.         - collection: the collection interface for the document
  2180.         - arg: an optional argument which may need to be included in
  2181.           the criteria (e.g. the level of a heading).
  2182.         '''
  2183.         role = [
  2184.             pyatspi.ROLE_LIST]
  2185.         state = [
  2186.             pyatspi.STATE_FOCUSABLE]
  2187.         stateMatch = collection.MATCH_NONE
  2188.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  2189.  
  2190.     
  2191.     def _listPredicate(self, obj, arg = None):
  2192.         '''The predicate to be used for verifying that the object
  2193.         obj is an (un)ordered list.
  2194.  
  2195.         Arguments:
  2196.         - obj: the accessible object under consideration.
  2197.         - arg: an optional argument which may need to be included in
  2198.           the criteria (e.g. the level of a heading).
  2199.         '''
  2200.         isMatch = False
  2201.         if obj and obj.getRole() == pyatspi.ROLE_LIST:
  2202.             isMatch = not obj.getState().contains(pyatspi.STATE_FOCUSABLE)
  2203.         
  2204.         return isMatch
  2205.  
  2206.     
  2207.     def _listPresentation(self, obj, arg = None):
  2208.         '''Presents the (un)ordered list or indicates that one was not
  2209.         found.
  2210.  
  2211.         Arguments:
  2212.         - obj: the accessible object under consideration.
  2213.         - arg: an optional argument which may need to be included in
  2214.           the criteria (e.g. the level of a heading).
  2215.         '''
  2216.         if obj:
  2217.             nItems = 0
  2218.             for child in obj:
  2219.                 if child.getRole() == pyatspi.ROLE_LIST_ITEM:
  2220.                     nItems += 1
  2221.                     continue
  2222.             
  2223.             itemString = ngettext('List with %d item', 'List with %d items', nItems) % nItems
  2224.             speech.speak(itemString)
  2225.             nestingLevel = 0
  2226.             parent = obj.parent
  2227.             while parent.getRole() == pyatspi.ROLE_LIST:
  2228.                 nestingLevel += 1
  2229.                 parent = parent.parent
  2230.             if nestingLevel:
  2231.                 speech.speak(_('Nesting level %d') % nestingLevel)
  2232.             
  2233.             (obj, characterOffset) = self._getCaretPosition(obj)
  2234.             self._setCaretPosition(obj, characterOffset)
  2235.             self._presentLine(obj, characterOffset)
  2236.         else:
  2237.             speech.speak(_('No more lists.'))
  2238.  
  2239.     
  2240.     def _listItemBindings(self):
  2241.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2242.         lists for navigating amongst items in an (un)ordered list.
  2243.         '''
  2244.         bindings = { }
  2245.         prevDesc = _('Goes to previous list item.')
  2246.         bindings['previous'] = [
  2247.             'i',
  2248.             settings.SHIFT_MODIFIER_MASK,
  2249.             prevDesc]
  2250.         nextDesc = _('Goes to next list item.')
  2251.         bindings['next'] = [
  2252.             'i',
  2253.             settings.NO_MODIFIER_MASK,
  2254.             nextDesc]
  2255.         return bindings
  2256.  
  2257.     
  2258.     def _listItemCriteria(self, collection, arg = None):
  2259.         '''Returns the MatchCriteria to be used for locating items in an
  2260.         (un)ordered list by collection.
  2261.  
  2262.         Arguments:
  2263.         - collection: the collection interface for the document
  2264.         - arg: an optional argument which may need to be included in
  2265.           the criteria (e.g. the level of a heading).
  2266.         '''
  2267.         role = [
  2268.             pyatspi.ROLE_LIST_ITEM]
  2269.         state = [
  2270.             pyatspi.STATE_FOCUSABLE]
  2271.         stateMatch = collection.MATCH_NONE
  2272.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  2273.  
  2274.     
  2275.     def _listItemPredicate(self, obj, arg = None):
  2276.         '''The predicate to be used for verifying that the object
  2277.         obj is an item in an (un)ordered list.
  2278.  
  2279.         Arguments:
  2280.         - obj: the accessible object under consideration.
  2281.         - arg: an optional argument which may need to be included in
  2282.           the criteria (e.g. the level of a heading).
  2283.         '''
  2284.         isMatch = False
  2285.         if obj and obj.getRole() == pyatspi.ROLE_LIST_ITEM:
  2286.             isMatch = not obj.getState().contains(pyatspi.STATE_FOCUSABLE)
  2287.         
  2288.         return isMatch
  2289.  
  2290.     
  2291.     def _listItemPresentation(self, obj, arg = None):
  2292.         '''Presents the (un)ordered list item or indicates that one was not
  2293.         found.
  2294.  
  2295.         Arguments:
  2296.         - obj: the accessible object under consideration.
  2297.         - arg: an optional argument which may need to be included in
  2298.           the criteria (e.g. the level of a heading).
  2299.         '''
  2300.         if obj:
  2301.             (obj, characterOffset) = self._getCaretPosition(obj)
  2302.             self._setCaretPosition(obj, characterOffset)
  2303.             self._presentLine(obj, characterOffset)
  2304.         else:
  2305.             speech.speak(_('No more list items.'))
  2306.  
  2307.     
  2308.     def _liveRegionBindings(self):
  2309.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2310.         lists for navigating amongst live regions.
  2311.         '''
  2312.         bindings = { }
  2313.         prevDesc = _('Goes to previous live region.')
  2314.         bindings['previous'] = [
  2315.             'r',
  2316.             settings.SHIFT_MODIFIER_MASK,
  2317.             prevDesc]
  2318.         nextDesc = _('Goes to next live region.')
  2319.         bindings['next'] = [
  2320.             'r',
  2321.             settings.NO_MODIFIER_MASK,
  2322.             nextDesc]
  2323.         desc = _('Goes to last live region.')
  2324.         bindings['last'] = [
  2325.             'y',
  2326.             settings.NO_MODIFIER_MASK,
  2327.             desc]
  2328.         return bindings
  2329.  
  2330.     
  2331.     def _liveRegionPredicate(self, obj, arg = None):
  2332.         '''The predicate to be used for verifying that the object
  2333.         obj is a live region.
  2334.  
  2335.         Arguments:
  2336.         - obj: the accessible object under consideration.
  2337.         - arg: an optional argument which may need to be included in
  2338.           the criteria (e.g. the level of a heading).
  2339.         '''
  2340.         isMatch = False
  2341.         regobjs = self._script.liveMngr.getLiveNoneObjects()
  2342.         if self._script.liveMngr.matchLiveRegion(obj) or obj in regobjs:
  2343.             isMatch = True
  2344.         
  2345.         return isMatch
  2346.  
  2347.     
  2348.     def _liveRegionPresentation(self, obj, arg = None):
  2349.         '''Presents the live region or indicates that one was not found.
  2350.  
  2351.         Arguments:
  2352.         - obj: the accessible object under consideration.
  2353.         - arg: an optional argument which may need to be included in
  2354.           the criteria (e.g. the level of a heading).
  2355.         '''
  2356.         if obj:
  2357.             if obj.getRole() == pyatspi.ROLE_LIST:
  2358.                 characterOffset = 0
  2359.             else:
  2360.                 (obj, characterOffset) = self._getCaretPosition(obj)
  2361.             self._setCaretPosition(obj, characterOffset)
  2362.             self._presentObject(obj, characterOffset)
  2363.             self._script.outlineAccessible(obj)
  2364.         else:
  2365.             speech.speak(_('No more live regions.'))
  2366.  
  2367.     
  2368.     def _paragraphBindings(self):
  2369.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2370.         lists for navigating amongst paragraphs.
  2371.         '''
  2372.         bindings = { }
  2373.         prevDesc = _('Goes to previous paragraph.')
  2374.         bindings['previous'] = [
  2375.             'p',
  2376.             settings.SHIFT_MODIFIER_MASK,
  2377.             prevDesc]
  2378.         nextDesc = _('Goes to next paragraph.')
  2379.         bindings['next'] = [
  2380.             'p',
  2381.             settings.NO_MODIFIER_MASK,
  2382.             nextDesc]
  2383.         return bindings
  2384.  
  2385.     
  2386.     def _paragraphCriteria(self, collection, arg = None):
  2387.         '''Returns the MatchCriteria to be used for locating paragraphs
  2388.         by collection.
  2389.  
  2390.         Arguments:
  2391.         - collection: the collection interface for the document
  2392.         - arg: an optional argument which may need to be included in
  2393.           the criteria (e.g. the level of a heading).
  2394.         '''
  2395.         role = [
  2396.             pyatspi.ROLE_PARAGRAPH]
  2397.         return MatchCriteria(collection, roles = role, applyPredicate = True)
  2398.  
  2399.     
  2400.     def _paragraphPredicate(self, obj, arg = None):
  2401.         '''The predicate to be used for verifying that the object
  2402.         obj is a paragraph.
  2403.  
  2404.         Arguments:
  2405.         - obj: the accessible object under consideration.
  2406.         - arg: an optional argument which may need to be included in
  2407.           the criteria (e.g. the level of a heading).
  2408.         '''
  2409.         isMatch = False
  2410.         if obj and obj.getRole() == pyatspi.ROLE_PARAGRAPH:
  2411.             
  2412.             try:
  2413.                 text = obj.queryText()
  2414.                 isMatch = text.characterCount > 2
  2415.  
  2416.         
  2417.         return isMatch
  2418.  
  2419.     
  2420.     def _paragraphPresentation(self, obj, arg = None):
  2421.         '''Presents the paragraph or indicates that one was not found.
  2422.  
  2423.         Arguments:
  2424.         - obj: the accessible object under consideration.
  2425.         - arg: an optional argument which may need to be included in
  2426.           the criteria (e.g. the level of a heading).
  2427.         '''
  2428.         if obj:
  2429.             (newObj, characterOffset) = self._getCaretPosition(obj)
  2430.             self._setCaretPosition(newObj, characterOffset)
  2431.             self._presentObject(obj, 0)
  2432.         else:
  2433.             speech.speak(_('No more paragraphs.'))
  2434.  
  2435.     
  2436.     def _radioButtonBindings(self):
  2437.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2438.         lists for navigating amongst radio buttons.
  2439.         '''
  2440.         bindings = { }
  2441.         prevDesc = _('Goes to previous radio button.')
  2442.         bindings['previous'] = [
  2443.             '',
  2444.             settings.NO_MODIFIER_MASK,
  2445.             prevDesc]
  2446.         nextDesc = _('Goes to next radio button.')
  2447.         bindings['next'] = [
  2448.             '',
  2449.             settings.NO_MODIFIER_MASK,
  2450.             nextDesc]
  2451.         return bindings
  2452.  
  2453.     
  2454.     def _radioButtonCriteria(self, collection, arg = None):
  2455.         '''Returns the MatchCriteria to be used for locating radio buttons
  2456.         by collection.
  2457.  
  2458.         Arguments:
  2459.         - collection: the collection interface for the document
  2460.         - arg: an optional argument which may need to be included in
  2461.           the criteria (e.g. the level of a heading).
  2462.         '''
  2463.         role = [
  2464.             pyatspi.ROLE_RADIO_BUTTON]
  2465.         state = [
  2466.             pyatspi.STATE_FOCUSABLE,
  2467.             pyatspi.STATE_SENSITIVE]
  2468.         stateMatch = collection.MATCH_ALL
  2469.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  2470.  
  2471.     
  2472.     def _radioButtonPredicate(self, obj, arg = None):
  2473.         '''The predicate to be used for verifying that the object
  2474.         obj is a radio button.
  2475.  
  2476.         Arguments:
  2477.         - obj: the accessible object under consideration.
  2478.         - arg: an optional argument which may need to be included in
  2479.           the criteria (e.g. the level of a heading).
  2480.         '''
  2481.         isMatch = False
  2482.         if obj and obj.getRole() == pyatspi.ROLE_RADIO_BUTTON:
  2483.             state = obj.getState()
  2484.             if state.contains(pyatspi.STATE_FOCUSABLE):
  2485.                 pass
  2486.             isMatch = state.contains(pyatspi.STATE_SENSITIVE)
  2487.         
  2488.         return isMatch
  2489.  
  2490.     
  2491.     def _radioButtonPresentation(self, obj, arg = None):
  2492.         '''Presents the radio button or indicates that one was not found.
  2493.  
  2494.         Arguments:
  2495.         - obj: the accessible object under consideration.
  2496.         - arg: an optional argument which may need to be included in
  2497.           the criteria (e.g. the level of a heading).
  2498.         '''
  2499.         if obj:
  2500.             obj.queryComponent().grabFocus()
  2501.         else:
  2502.             speech.speak(_('No more radio buttons.'))
  2503.  
  2504.     
  2505.     def _tableBindings(self):
  2506.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2507.         lists for navigating amongst tables.
  2508.         '''
  2509.         bindings = { }
  2510.         prevDesc = _('Goes to previous table.')
  2511.         bindings['previous'] = [
  2512.             't',
  2513.             settings.SHIFT_MODIFIER_MASK,
  2514.             prevDesc]
  2515.         nextDesc = _('Goes to next table.')
  2516.         bindings['next'] = [
  2517.             't',
  2518.             settings.NO_MODIFIER_MASK,
  2519.             nextDesc]
  2520.         return bindings
  2521.  
  2522.     
  2523.     def _tableCriteria(self, collection, arg = None):
  2524.         '''Returns the MatchCriteria to be used for locating tables
  2525.         by collection.
  2526.  
  2527.         Arguments:
  2528.         - collection: the collection interface for the document
  2529.         - arg: an optional argument which may need to be included in
  2530.           the criteria (e.g. the level of a heading).
  2531.         '''
  2532.         role = [
  2533.             pyatspi.ROLE_TABLE]
  2534.         return MatchCriteria(collection, roles = role, applyPredicate = True)
  2535.  
  2536.     
  2537.     def _tablePredicate(self, obj, arg = None):
  2538.         '''The predicate to be used for verifying that the object
  2539.         obj is a table.
  2540.  
  2541.         Arguments:
  2542.         - obj: the accessible object under consideration.
  2543.         - arg: an optional argument which may need to be included in
  2544.           the criteria (e.g. the level of a heading).
  2545.         '''
  2546.         if obj and obj.childCount and obj.getRole() == pyatspi.ROLE_TABLE:
  2547.             
  2548.             try:
  2549.                 return obj.queryTable().nRows > 0
  2550.  
  2551.         
  2552.         return False
  2553.  
  2554.     
  2555.     def _tablePresentation(self, obj, arg = None):
  2556.         '''Presents the table or indicates that one was not found.
  2557.  
  2558.         Arguments:
  2559.         - obj: the accessible object under consideration.
  2560.         - arg: an optional argument which may need to be included in
  2561.           the criteria (e.g. the level of a heading).
  2562.         '''
  2563.         if obj:
  2564.             caption = self._getTableCaption(obj)
  2565.             if caption:
  2566.                 speech.speak(caption)
  2567.             
  2568.             speech.speak(self._getTableDescription(obj))
  2569.             cell = obj.queryTable().getAccessibleAt(0, 0)
  2570.             self.lastTableCell = [
  2571.                 0,
  2572.                 0]
  2573.             (cell, characterOffset) = self._getCaretPosition(cell)
  2574.             self._setCaretPosition(cell, characterOffset)
  2575.             self._presentObject(cell, characterOffset)
  2576.         else:
  2577.             speech.speak(_('No more tables.'))
  2578.  
  2579.     
  2580.     def _tableCellBindings(self):
  2581.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2582.         lists for navigating spatially amongst table cells.
  2583.         '''
  2584.         bindings = { }
  2585.         desc = _('Goes left one cell.')
  2586.         bindings['left'] = [
  2587.             'Left',
  2588.             settings.SHIFT_ALT_MODIFIER_MASK,
  2589.             desc]
  2590.         desc = _('Goes right one cell.')
  2591.         bindings['right'] = [
  2592.             'Right',
  2593.             settings.SHIFT_ALT_MODIFIER_MASK,
  2594.             desc]
  2595.         desc = _('Goes up one cell.')
  2596.         bindings['up'] = [
  2597.             'Up',
  2598.             settings.SHIFT_ALT_MODIFIER_MASK,
  2599.             desc]
  2600.         desc = _('Goes down one cell.')
  2601.         bindings['down'] = [
  2602.             'Down',
  2603.             settings.SHIFT_ALT_MODIFIER_MASK,
  2604.             desc]
  2605.         desc = _('Goes to the first cell in a table.')
  2606.         bindings['first'] = [
  2607.             'Home',
  2608.             settings.SHIFT_ALT_MODIFIER_MASK,
  2609.             desc]
  2610.         desc = _('Goes to the last cell in a table.')
  2611.         bindings['last'] = [
  2612.             'End',
  2613.             settings.SHIFT_ALT_MODIFIER_MASK,
  2614.             desc]
  2615.         return bindings
  2616.  
  2617.     
  2618.     def _tableCellCriteria(self, collection, arg = None):
  2619.         '''Returns the MatchCriteria to be used for locating table cells
  2620.         by collection.
  2621.  
  2622.         Arguments:
  2623.         - collection: the collection interface for the document
  2624.         - arg: an optional argument which may need to be included in
  2625.           the criteria (e.g. the level of a heading).
  2626.         '''
  2627.         role = [
  2628.             pyatspi.ROLE_TABLE_CELL]
  2629.         return MatchCriteria(collection, roles = role)
  2630.  
  2631.     
  2632.     def _tableCellPredicate(self, obj, arg = None):
  2633.         '''The predicate to be used for verifying that the object
  2634.         obj is a table cell.
  2635.  
  2636.         Arguments:
  2637.         - obj: the accessible object under consideration.
  2638.         - arg: an optional argument which may need to be included in
  2639.           the criteria (e.g. the level of a heading).
  2640.         '''
  2641.         if obj:
  2642.             pass
  2643.         return obj.getRole() == pyatspi.ROLE_TABLE_CELL
  2644.  
  2645.     
  2646.     def _tableCellPresentation(self, cell, arg):
  2647.         '''Presents the table cell or indicates that one was not found.
  2648.  
  2649.         Arguments:
  2650.         - obj: the accessible object under consideration.
  2651.         - arg: an optional argument which may need to be included in
  2652.           the criteria (e.g. the level of a heading).
  2653.         '''
  2654.         if not cell:
  2655.             return None
  2656.         if settings.speakCellHeaders:
  2657.             self._presentCellHeaders(cell, arg)
  2658.         
  2659.         (obj, characterOffset) = self._getCaretPosition(cell)
  2660.         self._setCaretPosition(obj, characterOffset)
  2661.         self._script.updateBraille(obj)
  2662.         blank = self._isBlankCell(cell)
  2663.         if not blank:
  2664.             self._presentObject(cell, 0)
  2665.         else:
  2666.             speech.speak(_('blank'))
  2667.         if settings.speakCellCoordinates:
  2668.             (row, col) = self.getCellCoordinates(cell)
  2669.             speech.speak(_('Row %d, column %d.') % (row + 1, col + 1))
  2670.         
  2671.         spanString = self._getCellSpanInfo(cell)
  2672.         if spanString and settings.speakCellSpan:
  2673.             speech.speak(spanString)
  2674.         
  2675.  
  2676.     
  2677.     def _unvisitedLinkBindings(self):
  2678.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2679.         lists for navigating amongst unvisited links.
  2680.         '''
  2681.         bindings = { }
  2682.         prevDesc = _('Goes to previous unvisited link.')
  2683.         bindings['previous'] = [
  2684.             'u',
  2685.             settings.SHIFT_MODIFIER_MASK,
  2686.             prevDesc]
  2687.         nextDesc = _('Goes to next unvisited link.')
  2688.         bindings['next'] = [
  2689.             'u',
  2690.             settings.NO_MODIFIER_MASK,
  2691.             nextDesc]
  2692.         return bindings
  2693.  
  2694.     
  2695.     def _unvisitedLinkCriteria(self, collection, arg = None):
  2696.         '''Returns the MatchCriteria to be used for locating unvisited links
  2697.         by collection.
  2698.  
  2699.         Arguments:
  2700.         - collection: the collection interface for the document
  2701.         - arg: an optional argument which may need to be included in
  2702.           the criteria (e.g. the level of a heading).
  2703.         '''
  2704.         role = [
  2705.             pyatspi.ROLE_LINK]
  2706.         state = [
  2707.             pyatspi.STATE_VISITED]
  2708.         stateMatch = collection.MATCH_NONE
  2709.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  2710.  
  2711.     
  2712.     def _unvisitedLinkPredicate(self, obj, arg = None):
  2713.         '''The predicate to be used for verifying that the object
  2714.         obj is an unvisited link.
  2715.  
  2716.         Arguments:
  2717.         - obj: the accessible object under consideration.
  2718.         - arg: an optional argument which may need to be included in
  2719.           the criteria (e.g. the level of a heading).
  2720.         '''
  2721.         isMatch = False
  2722.         if obj and obj.getRole() == pyatspi.ROLE_LINK:
  2723.             isMatch = not obj.getState().contains(pyatspi.STATE_VISITED)
  2724.         
  2725.         return isMatch
  2726.  
  2727.     
  2728.     def _unvisitedLinkPresentation(self, obj, arg = None):
  2729.         '''Presents the unvisited link or indicates that one was not
  2730.         found.
  2731.  
  2732.         Arguments:
  2733.         - obj: the accessible object under consideration.
  2734.         - arg: an optional argument which may need to be included in
  2735.           the criteria (e.g. the level of a heading).
  2736.         '''
  2737.         if obj:
  2738.             (obj, characterOffset) = self._getCaretPosition(obj)
  2739.             self._setCaretPosition(obj, characterOffset)
  2740.             self._presentObject(obj, characterOffset)
  2741.         else:
  2742.             speech.speak(_('No more unvisited links.'))
  2743.  
  2744.     
  2745.     def _visitedLinkBindings(self):
  2746.         '''Returns a dictionary of [keysymstring, modifiers, description]
  2747.         lists for navigating amongst visited links.
  2748.         '''
  2749.         bindings = { }
  2750.         prevDesc = _('Goes to previous visited link.')
  2751.         bindings['previous'] = [
  2752.             'v',
  2753.             settings.SHIFT_MODIFIER_MASK,
  2754.             prevDesc]
  2755.         nextDesc = _('Goes to next visited link.')
  2756.         bindings['next'] = [
  2757.             'v',
  2758.             settings.NO_MODIFIER_MASK,
  2759.             nextDesc]
  2760.         return bindings
  2761.  
  2762.     
  2763.     def _visitedLinkCriteria(self, collection, arg = None):
  2764.         '''Returns the MatchCriteria to be used for locating visited links
  2765.         by collection.
  2766.  
  2767.         Arguments:
  2768.         - collection: the collection interface for the document
  2769.         - arg: an optional argument which may need to be included in
  2770.           the criteria (e.g. the level of a heading).
  2771.         '''
  2772.         role = [
  2773.             pyatspi.ROLE_LINK]
  2774.         state = [
  2775.             pyatspi.STATE_VISITED]
  2776.         stateMatch = collection.MATCH_ANY
  2777.         return MatchCriteria(collection, states = state, matchStates = stateMatch, roles = role)
  2778.  
  2779.     
  2780.     def _visitedLinkPredicate(self, obj, arg = None):
  2781.         '''The predicate to be used for verifying that the object
  2782.         obj is a visited link.
  2783.  
  2784.         Arguments:
  2785.         - obj: the accessible object under consideration.
  2786.         - arg: an optional argument which may need to be included in
  2787.           the criteria (e.g. the level of a heading).
  2788.         '''
  2789.         isMatch = False
  2790.         if obj and obj.getRole() == pyatspi.ROLE_LINK:
  2791.             isMatch = obj.getState().contains(pyatspi.STATE_VISITED)
  2792.         
  2793.         return isMatch
  2794.  
  2795.     
  2796.     def _visitedLinkPresentation(self, obj, arg = None):
  2797.         '''Presents the visited link or indicates that one was not
  2798.         found.
  2799.  
  2800.         Arguments:
  2801.         - obj: the accessible object under consideration.
  2802.         - arg: an optional argument which may need to be included in
  2803.           the criteria (e.g. the level of a heading).
  2804.         '''
  2805.         if obj:
  2806.             (obj, characterOffset) = self._getCaretPosition(obj)
  2807.             self._setCaretPosition(obj, characterOffset)
  2808.             self._presentObject(obj, characterOffset)
  2809.         else:
  2810.             speech.speak(_('No more visited links.'))
  2811.  
  2812.  
  2813.